碰到Requires: llvm-toolset-7-clang >= 4.0.1这种报错,很多人第一反应是“装个数据库怎么还跟编译器扯上关系了”。我当年第一次在 CentOS 7 上装 PostgreSQL 11 也愣了半天,后来把 RPM 依赖链和 PostgreSQL 的 JIT 机制都翻了一遍才彻底搞明白。这篇就把这个报错的来龙去脉、排查过程和几种可行的解决方案一次性讲清楚,给以后还会踩到同类坑的人留个完整笔记。先说结论:这个报错不是你的系统缺了什么奇怪的软件,也不是 PostgreSQL 本身的安装包坏了,而是PostgreSQL 11 之后的官方 RPM 在编译时开启了 LLVM JIT 加速功能,所以在 RPM 元数据里写死了对 LLVM/Clang 工具集的依赖。你的机器上没有启用提供llvm-toolset-7-clang这个包的软件仓库,yum 找不到依赖,自然就会直接报“缺少 Requires”然后拒绝安装。下面拆开讲。1. 这个报错背后的依赖链:为什么 PostgreSQL 非要一个 clang1.1 llvm-toolset-7 是什么,它跟普通 llvm 包有什么区别先解决最直观的疑惑:llvm-toolset-7-clang到底是个什么东西?在 RHEL/CentOS 7 体系里,软件包的命名遵循一个约定:llvm-toolset-7是一个“软件集(Software Collection,SCL)”,它本身不是某个单一软件的版本,而是一整套工具链的合集。这个集合里包含的是Clang 编译器、LLVM 编译器基础设施、LLDB 调试器、libomp 运行时库等一系列 LLVM 生态组件。软件集版本号是 7,但里面 Clang 的实际版本是 4.0.1,LLVM 本身则基于 5.0。这就是报错里“>= 4.0.1”这个数字的由来。RPM 依赖写的是包名llvm-toolset-7-clang加版本号4.0.1,而 SCL 仓库里正好有对应版本。也就是说,这个依赖其实是非常精确的,不是随便拿一个“新一点的 clang”就能顶替。在 RHEL 7 和 CentOS 7 上,这类 SCL 软件集默认不会启用。RHEL 用户要想用,得在订阅管理里单独启用“软件集合”通道;CentOS 用户则需要安装centos-release-scl这个仓库配置文件包,把centos-sclo-rh仓库打开。很多人第一次翻车,就是因为从未装过这个包。1.2 PostgreSQL 11 引入的 JIT 编译机制PostgreSQL 11 是一个分水岭版本,它引入了基于 LLVM 的 JIT(Just-In-Time)即时编译。所谓 JIT,通俗说就是数据库在执行某些表达式计算和元组投影时,把“解释执行”的代码在运行时编译成机器码,减少 CPU 在重复计算上的开销。JIT 对哪些场景有用?实测里,复杂分析型查询、带有大量表达式求值的查询、需要反复解包大量行数据的查询,收益会比较明显,有些案例能提速 20% 到 30%。但对简单的点查、短事务、OLTP 类型的小查询,JIT 几乎帮不上忙,反而会因为编译本身消耗额外 CPU 时长。PostgreSQL 的官方代码里,JIT 编译功能依赖 LLVM 库。而发行版打包者在做 RPM 时,如果配置了--with-llvm,rpmbuild 就会根据编译环境自动生成对应的依赖关系,把这个依赖写进.spec文件的Requires字段。PGDG 的 PostgreSQL 11 RPM 就是这么干 的。于是安装时,RPM 依赖解析器会告诉你:你需要一个名为llvm-toolset-7-clang且版本不低于 4.0.1 的包。1.3 为什么不是自动装上,而是直接报错很多人会问:yum 不是能自动装依赖吗?这里的关键在于:yum 只能从“当前已启用的软件仓库”里寻找依赖包,不会跑到互联网上漫无目的地搜索。你的系统启用了 base、updates、extras,最多再加一个 PGDG 的 PostgreSQL 仓库。在 PGDG 仓库里,llvm-toolset-7-clang这个东西并不存在;在 base 和 extras 里也没有。yum 在所有已启用仓库里扫描一圈后找不到这个名字的包,就只能报出最原始的Requires错误。这就好比你点了盘番茄炒蛋,冰箱里只有鸡蛋,没有番茄,厨房也不会自动去隔壁超市进货——它只会告诉你“缺番茄”。所以,要解决这个报错,本质上就两件事:要么给 yum 提供一个能买到“番茄”的仓库,要么换一道不依赖“番茄”的菜。2. 现场复现与排查链路:先搞清楚是谁在要这个依赖2.1 确认 PostgreSQL 包到底来自哪个仓库安装报错之后,第一步不是急着找解决命令,而是先确认你打算装的 PostgreSQL 版本和来源。不同来源的包,依赖策略差别很大。在 CentOS 7 上,系统自带的 base 仓库里只有老版本的 PostgreSQL 9.2,那个版本没有 JIT,根本没有这个依赖。你装的如果是 PGDG 提供的postgresql11-server,那 RPM 包名里通常会带着pgdg字样,例如postgresql11-server-11.5-1PGDG.rhel7.x86_64。可以利用 yum 的--showduplicates来确认,也可以直接看安装命令输出里的(pgdg11)等仓库标签:yum list --showduplicates 'postgresql11-server'输出里如果包名末尾带@pgdg11或pgdg字样,就可以确定依赖和 PGDG 有关。之后用yum deplist看完整的依赖树:yum deplist postgresql11-server | grep -i llvm你会在结果里看到类似这样的一行:dependency: llvm-toolset-7-clang provider: llvm-toolset-7-clang.x86_64 4.0.1-1.el7这说明依赖关系确实存在,并且已经有一个“理论上”的 provider,只是你的仓库里没有启用它。2.2 从 RPM 文件层面直接验证依赖如果已经下载了 RPM 但没有安装成功,可以用rpm -qpR直接查看这个包注册表的依赖信息。这是排查 RPM 依赖最硬核的手段,不需要把包装进系统:# 先下载这个包,但不要安装 yumdownloader --enablerepo=pgdg11 postgresql11-server # 查看依赖 rpm -qpR postgresql11-server-11.5-1PGDG.rhel7.x86_64.rpm | grep -E 'llvm|clang'结果里十有八九会显出:llvm-toolset-7-clang >= 4.0.1这一步能把问题彻底定位在 RPM 元数据层面,而不是你的系统“缺少编译器”。也就能避免瞎折腾 GCC、g++ 之类的无用操作。2.3 检查当前仓库里是否真有这个包确认了依赖之后,再用 yum 搜索一遍同名包,看看它到底在哪个仓库:yum list available 'llvm-toolset*'如果输出是“没有可用软件包”或者提示找不到对应仓库,原因基本就是 SCL 仓库没启用。顺着这个思路,可以查看当前启用的仓库:yum repolist正常情况下应该看到base/7/x86_64、updates/7/x86_64之类的仓库名。如果没有centos-sclo-rh,那就直接去装centos-release-scl这个仓库配置包。这一步做完,整个报错的逻辑链就闭环了:PostgreSQL 11 RPM 需要llvm-toolset-7-clang >= 4.0.1这个包在 CentOS 7 的 SCL 仓库里你没启用 SCL 仓库yum 找不到依赖 → 报错启用 SCL 仓库 → 问题消失3. 实测有效的三条解决路径:从低风险到高风险3.1 路径 A:补装 SCL 软件集源,让依赖自动被解析这是我强烈推荐的标准做法。它不仅解决当前这一个包,还顺便把 SCL 系列仓库补齐了,以后 PostgreSQL 12、13 等大版本升级时再遇到同类依赖,也能直接命中。在 CentOS 7 上执行:# 安装仓库配置包 yum install -y centos-release-scl # 刷新缓存 yum makecache # 手动验证一下依赖包是否可见 yum install -y llvm-toolset-7-clang # 回到 PostgreSQL 安装,此时依赖能被自动解析 yum install -y postgresql11-server执行完最后一条命令,yum 会自己计算出依赖,拉取llvm-toolset-7-clang以及它依赖的llvm-toolset-7-libllvm、llvm-toolset-7-compiler-rt等包。整个过程不需要手动指定路径,也不需要改任何 RPM 元数据。安装完成后,可以用下面命令验证依赖状态:rpm -q llvm-toolset-7-clangRHEL 7 用户稍微不同:需要先在订阅管理页面启用“Software Collections”通道,然后执行subscription-manager repos --enable rhel-server-rhscl-7-rpms,再走同样的 yum 流程。这里不再展开,因为 CentOS 用户占了绝大多数。3.2 路径 B:从源码编译并禁用 JIT,彻底摆脱对 LLVM 的依赖如果你就是不想让数据库和一堆编译器工具链扯上关系,或者你的生产环境对包来源有严格限制,不信任 SCL 仓库,那可以考虑关闭 JIT 构建选项,从源码自己编一个 PostgreSQL。源码安装也没有想象中复杂,大致流程如下:# 下载 PostgreSQL 11 源码 wget https://ftp.postgresql.org/pub/source/v11.21/postgresql-11.21.tar.bz2 tar xjf postgresql-11.21.tar.bz2 cd postgresql-11.21 # 核心参数:--without-llvm 表示不启用 JIT ./configure --prefix=/usr/local/pgsql-11 --without-llvm make -j$(nproc) make install这一步所以能绕开报错,是因为 PostgreSQL 的 configure 脚本在检测不到 LLVM 或者显式指定--without-llvm时,不会把 JIT 相关代码编进去,生成的 RPM 或直接安装的二进制也就没有对 LLVM 的运行期依赖。但代价也很明显:源码安装不会自动帮你创建系统服务文件、数据目录、日志轮转配置,后续这些都得自己手工补。而且以后要做yum update式的统一升级,也不会覆盖你手工安装的版本。生产环境如果对可维护性要求比较高,不建议为了省一个依赖选择这条路。另外一个折中方案是:用 PostgreSQL 的官方源码 RPM 做本地 rebuild,在.spec文件里去掉--with-llvm的构建参数。这样可以保留 RPM 的安装轨迹和可卸载性,但构建过程需要安装一整套 rpmbuild 环境,流程偏长,适合有打包经验的运维人员。3.3 路径 C:手动下载并安装缺失的 LLVM 相关 RPM如果你已经启用了某些内网镜像,但不想全局开启 SCL 仓库,也可以临时指定仓库来安装依赖包:yum install -y --enablerepo=centos-sclo-rh llvm-toolset-7-clang或者用yumdownloader --resolve把依赖包下载到本地再手动安装:mkdir -p /root/llvm-rpms && cd /root/llvm-rpms yumdownloader --enablerepo=centos-sclo-rh --resolve llvm-toolset-7-clang rpm -Uvh *.rpm这种方法最大的问题在于,一旦离开 yum 仓库解析机制,后续 PostgreSQL 小版本升级时,依赖仍然会断。而且手动rpm -Uvh如果忽略了某个传递依赖,比如没装scl-utils、llvm-toolset-7-libllvm,可能在装完后运行时才报错,排查成本更高。所以我只把它当作临时环境里的应急手段,不建议拿到长期维护的服务器上使用。3.4 三条路径的适用范围对比方案操作难度是否需要额外仓库是否保留 JIT 能力风险点路径 A:补装 SCL 源低需要 SCL 仓库保留仓库维护依赖外部源,但属于标准做法路径 B:源码编译禁 JIT较高不需要不保留脱离包管理,升级靠手动路径 C:手动补 RPM中需要 SCL 仓库且手动指定保留依赖链容易遗漏,应急不长久如果你问我实际会选择哪个,答案基本是路径 A。绝大多数情况下,让 yum 在仓库层面把依赖补齐是最符合 Linux 生态习惯的做法,后续维护成本也最低。4. 装好之后还要注意的几件事:JIT、版本升级和运维习惯4.1 检查 JIT 到底有没有真正生效依赖安装完成、PostgreSQL 启动之后,建议顺手确认一下 JIT 的实际情况。很多朋友以为“装上了就没问题”,其实可以进一步验证。用超级用户连进数据库执行:SELECT name, setting FROM pg_settings WHERE name = 'jit';setting如果是on,说明 JIT 功能处于可用状态。再执行一个稍复杂的查询并打开EXPLAIN:EXPLAIN (ANALYZE, VERBOSE) SELECT count(*), sum(price * quantity) FROM orders WHERE created_at > '2024-01-01' GROUP BY customer_id;输出里如果出现JIT: Functions: 5 Options: Inlining true, Optimization true之类的信息,就说明这个查询确实被 JIT 编译了。如果查询很快就返回,或者完全没有 JIT 字样,也不用担心,PostgreSQL 自己会根据查询代价估估算是否值得用 JIT。如果你的业务以短事务 OLTP 为主,在postgresql.conf里可以关掉 JIT:jit = off需要提醒的是:jit = off只是关闭运行期 JIT 功能,不能解决 RPM 依赖问题。因为二进制文件在编译时已经链接到 LLVM 库,安装层面的 RPM 依赖依然存在,你把llvm-toolset-7-clang卸掉,PostgreSQL 即使不执行 JIT,启动时也可能因为加载不到libLLVM而失败。这一点经常被误解,尤其是一些“既然不用 JIT 就卸载依赖”的操作,很容易把整库搞挂。4.2 大版本升级时,依赖可能会变名字PostgreSQL 的大版本升级,比如从 11 升到 13,往往意味着 JIT 依赖包也会变化。在 CentOS 7 上不同 PGDG 大版本对应的 LLVM 工具集不同,比如 PostgreSQL 12、13 可能依赖llvm-toolset-9-clang或更高版本的工具集,甚至在 RHEL 8 上会改用llvm5.0这类独立包名。这带来的实际影响是:升级之前要先跑一次yum deplist,看清新版本包对 LLVM 的依赖到底落在哪个包上,再对照已启用的仓库检查有没有这个 provider。否则升级画面会重现,只不过包名从llvm-toolset-7-clang变成别的名字。我见过不少搞坏的生产环境,都是因为升级前没看依赖,直接yum update postgresql*,结果新包要求依赖满足不了,数据库版本还停在旧版本上,仓促之间进退两难。4.3 运维习惯:别再依赖“强制忽略依赖”这种操作做系统运维越久,越会觉得rpm --nodeps这种参数应该谨慎使用。在 PostgreSQL 的依赖问题上,--nodeps确实可以让安装跳过检测,但代价是:后续任何用 RPM 解析依赖的工具都可能半瘫痪缺失的库文件直到进程启动时才暴露你无法向审计或同事解释“为什么这个包是这么装进来的”真要给生产服务器装软件,正确的姿势是:先把仓库、订阅、镜像源这些基础设施理顺,再谈具体安装。像这次碰到的llvm-toolset-7-clang,本质上就是一个“仓库基础设施不完整”导致的问题,远不是 PostgreSQL 或者 LLVM 本身的锅。如果你在内网离线环境,仓库基础设施更得多留个心眼:找一台能联网的机器把 SCL 相关 RPM 拉到本地,建一个内部 yum 源,定期同步。这样既解决了依赖,也符合离线交付的合规要求。4.4 新系统上这个问题的形态会不一样如果你已经用上了 CentOS 8、Rocky Linux 8 或者 AlmaLinux 8 这类新系统,同样的报错概率会小很多。因为在 8 系列里,LLVM/Clang 直接以llvm、clang包的形式存在于系统仓库中,dnf install llvm clang就能解决,不需要软件集这个概念。PGDG 在 RHEL 8/Rocky 8 上的 PostgreSQL 13 依赖通常也会落到更直接的 LLVM 包上。但这不代表新系统完全没坑。RHEL 8 开始引入了模块流(AppStream),PostgreSQL 的版本选择比 7 代复杂得多,安装前要确认你选的是 PGDG 源还是 AppStream 内置版本,两者的升级路径和维护方式完全不同。如果从 CentOS 7 迁移到 Rocky Linux 8,还要注意旧数据目录里某些插件和新版本编译选项不一致的问题。这些属于迁移专题,这里不展开,但原则是一样的:先把源和依赖彻底搞明白再动手。我个人的习惯是,在 CentOS/RHEL 系机器上安装任何需要外部依赖的软件时,先花一分钟跑一下yum deplist,再用yum repolist对照检查。很多看着诡异的报错,最后都能归结到“仓库没配齐”这一句上。下次你再看到Requires: llvm-toolset-7-clang >= 4.0.1,就知道该往哪个方向查了。
碰到Requires: llvm-toolset-7-clang >= 4.0.1这种报错,很多人第一反应是“装个数据库怎么还跟编译器扯上关系了”。我当年第一次在 CentOS 7 上装 PostgreSQL 11 也愣了半天,后来把 RPM 依赖链和 PostgreSQL 的 JIT 机制都翻了一遍才彻底搞明白。这篇就把这个报错的来龙去脉、排查过程和几种可行的解决方案一次性讲清楚,给以后还会踩到同类坑的人留个完整笔记。先说结论:这个报错不是你的系统缺了什么奇怪的软件,也不是 PostgreSQL 本身的安装包坏了,而是PostgreSQL 11 之后的官方 RPM 在编译时开启了 LLVM JIT 加速功能,所以在 RPM 元数据里写死了对 LLVM/Clang 工具集的依赖。你的机器上没有启用提供llvm-toolset-7-clang这个包的软件仓库,yum 找不到依赖,自然就会直接报“缺少 Requires”然后拒绝安装。下面拆开讲。1. 这个报错背后的依赖链:为什么 PostgreSQL 非要一个 clang1.1 llvm-toolset-7 是什么,它跟普通 llvm 包有什么区别先解决最直观的疑惑:llvm-toolset-7-clang到底是个什么东西?在 RHEL/CentOS 7 体系里,软件包的命名遵循一个约定:llvm-toolset-7是一个“软件集(Software Collection,SCL)”,它本身不是某个单一软件的版本,而是一整套工具链的合集。这个集合里包含的是Clang 编译器、LLVM 编译器基础设施、LLDB 调试器、libomp 运行时库等一系列 LLVM 生态组件。软件集版本号是 7,但里面 Clang 的实际版本是 4.0.1,LLVM 本身则基于 5.0。这就是报错里“>= 4.0.1”这个数字的由来。RPM 依赖写的是包名llvm-toolset-7-clang加版本号4.0.1,而 SCL 仓库里正好有对应版本。也就是说,这个依赖其实是非常精确的,不是随便拿一个“新一点的 clang”就能顶替。在 RHEL 7 和 CentOS 7 上,这类 SCL 软件集默认不会启用。RHEL 用户要想用,得在订阅管理里单独启用“软件集合”通道;CentOS 用户则需要安装centos-release-scl这个仓库配置文件包,把centos-sclo-rh仓库打开。很多人第一次翻车,就是因为从未装过这个包。1.2 PostgreSQL 11 引入的 JIT 编译机制PostgreSQL 11 是一个分水岭版本,它引入了基于 LLVM 的 JIT(Just-In-Time)即时编译。所谓 JIT,通俗说就是数据库在执行某些表达式计算和元组投影时,把“解释执行”的代码在运行时编译成机器码,减少 CPU 在重复计算上的开销。JIT 对哪些场景有用?实测里,复杂分析型查询、带有大量表达式求值的查询、需要反复解包大量行数据的查询,收益会比较明显,有些案例能提速 20% 到 30%。但对简单的点查、短事务、OLTP 类型的小查询,JIT 几乎帮不上忙,反而会因为编译本身消耗额外 CPU 时长。PostgreSQL 的官方代码里,JIT 编译功能依赖 LLVM 库。而发行版打包者在做 RPM 时,如果配置了--with-llvm,rpmbuild 就会根据编译环境自动生成对应的依赖关系,把这个依赖写进.spec文件的Requires字段。PGDG 的 PostgreSQL 11 RPM 就是这么干 的。于是安装时,RPM 依赖解析器会告诉你:你需要一个名为llvm-toolset-7-clang且版本不低于 4.0.1 的包。1.3 为什么不是自动装上,而是直接报错很多人会问:yum 不是能自动装依赖吗?这里的关键在于:yum 只能从“当前已启用的软件仓库”里寻找依赖包,不会跑到互联网上漫无目的地搜索。你的系统启用了 base、updates、extras,最多再加一个 PGDG 的 PostgreSQL 仓库。在 PGDG 仓库里,llvm-toolset-7-clang这个东西并不存在;在 base 和 extras 里也没有。yum 在所有已启用仓库里扫描一圈后找不到这个名字的包,就只能报出最原始的Requires错误。这就好比你点了盘番茄炒蛋,冰箱里只有鸡蛋,没有番茄,厨房也不会自动去隔壁超市进货——它只会告诉你“缺番茄”。所以,要解决这个报错,本质上就两件事:要么给 yum 提供一个能买到“番茄”的仓库,要么换一道不依赖“番茄”的菜。2. 现场复现与排查链路:先搞清楚是谁在要这个依赖2.1 确认 PostgreSQL 包到底来自哪个仓库安装报错之后,第一步不是急着找解决命令,而是先确认你打算装的 PostgreSQL 版本和来源。不同来源的包,依赖策略差别很大。在 CentOS 7 上,系统自带的 base 仓库里只有老版本的 PostgreSQL 9.2,那个版本没有 JIT,根本没有这个依赖。你装的如果是 PGDG 提供的postgresql11-server,那 RPM 包名里通常会带着pgdg字样,例如postgresql11-server-11.5-1PGDG.rhel7.x86_64。可以利用 yum 的--showduplicates来确认,也可以直接看安装命令输出里的(pgdg11)等仓库标签:yum list --showduplicates 'postgresql11-server'输出里如果包名末尾带@pgdg11或pgdg字样,就可以确定依赖和 PGDG 有关。之后用yum deplist看完整的依赖树:yum deplist postgresql11-server | grep -i llvm你会在结果里看到类似这样的一行:dependency: llvm-toolset-7-clang provider: llvm-toolset-7-clang.x86_64 4.0.1-1.el7这说明依赖关系确实存在,并且已经有一个“理论上”的 provider,只是你的仓库里没有启用它。2.2 从 RPM 文件层面直接验证依赖如果已经下载了 RPM 但没有安装成功,可以用rpm -qpR直接查看这个包注册表的依赖信息。这是排查 RPM 依赖最硬核的手段,不需要把包装进系统:# 先下载这个包,但不要安装 yumdownloader --enablerepo=pgdg11 postgresql11-server # 查看依赖 rpm -qpR postgresql11-server-11.5-1PGDG.rhel7.x86_64.rpm | grep -E 'llvm|clang'结果里十有八九会显出:llvm-toolset-7-clang >= 4.0.1这一步能把问题彻底定位在 RPM 元数据层面,而不是你的系统“缺少编译器”。也就能避免瞎折腾 GCC、g++ 之类的无用操作。2.3 检查当前仓库里是否真有这个包确认了依赖之后,再用 yum 搜索一遍同名包,看看它到底在哪个仓库:yum list available 'llvm-toolset*'如果输出是“没有可用软件包”或者提示找不到对应仓库,原因基本就是 SCL 仓库没启用。顺着这个思路,可以查看当前启用的仓库:yum repolist正常情况下应该看到base/7/x86_64、updates/7/x86_64之类的仓库名。如果没有centos-sclo-rh,那就直接去装centos-release-scl这个仓库配置包。这一步做完,整个报错的逻辑链就闭环了:PostgreSQL 11 RPM 需要llvm-toolset-7-clang >= 4.0.1这个包在 CentOS 7 的 SCL 仓库里你没启用 SCL 仓库yum 找不到依赖 → 报错启用 SCL 仓库 → 问题消失3. 实测有效的三条解决路径:从低风险到高风险3.1 路径 A:补装 SCL 软件集源,让依赖自动被解析这是我强烈推荐的标准做法。它不仅解决当前这一个包,还顺便把 SCL 系列仓库补齐了,以后 PostgreSQL 12、13 等大版本升级时再遇到同类依赖,也能直接命中。在 CentOS 7 上执行:# 安装仓库配置包 yum install -y centos-release-scl # 刷新缓存 yum makecache # 手动验证一下依赖包是否可见 yum install -y llvm-toolset-7-clang # 回到 PostgreSQL 安装,此时依赖能被自动解析 yum install -y postgresql11-server执行完最后一条命令,yum 会自己计算出依赖,拉取llvm-toolset-7-clang以及它依赖的llvm-toolset-7-libllvm、llvm-toolset-7-compiler-rt等包。整个过程不需要手动指定路径,也不需要改任何 RPM 元数据。安装完成后,可以用下面命令验证依赖状态:rpm -q llvm-toolset-7-clangRHEL 7 用户稍微不同:需要先在订阅管理页面启用“Software Collections”通道,然后执行subscription-manager repos --enable rhel-server-rhscl-7-rpms,再走同样的 yum 流程。这里不再展开,因为 CentOS 用户占了绝大多数。3.2 路径 B:从源码编译并禁用 JIT,彻底摆脱对 LLVM 的依赖如果你就是不想让数据库和一堆编译器工具链扯上关系,或者你的生产环境对包来源有严格限制,不信任 SCL 仓库,那可以考虑关闭 JIT 构建选项,从源码自己编一个 PostgreSQL。源码安装也没有想象中复杂,大致流程如下:# 下载 PostgreSQL 11 源码 wget https://ftp.postgresql.org/pub/source/v11.21/postgresql-11.21.tar.bz2 tar xjf postgresql-11.21.tar.bz2 cd postgresql-11.21 # 核心参数:--without-llvm 表示不启用 JIT ./configure --prefix=/usr/local/pgsql-11 --without-llvm make -j$(nproc) make install这一步所以能绕开报错,是因为 PostgreSQL 的 configure 脚本在检测不到 LLVM 或者显式指定--without-llvm时,不会把 JIT 相关代码编进去,生成的 RPM 或直接安装的二进制也就没有对 LLVM 的运行期依赖。但代价也很明显:源码安装不会自动帮你创建系统服务文件、数据目录、日志轮转配置,后续这些都得自己手工补。而且以后要做yum update式的统一升级,也不会覆盖你手工安装的版本。生产环境如果对可维护性要求比较高,不建议为了省一个依赖选择这条路。另外一个折中方案是:用 PostgreSQL 的官方源码 RPM 做本地 rebuild,在.spec文件里去掉--with-llvm的构建参数。这样可以保留 RPM 的安装轨迹和可卸载性,但构建过程需要安装一整套 rpmbuild 环境,流程偏长,适合有打包经验的运维人员。3.3 路径 C:手动下载并安装缺失的 LLVM 相关 RPM如果你已经启用了某些内网镜像,但不想全局开启 SCL 仓库,也可以临时指定仓库来安装依赖包:yum install -y --enablerepo=centos-sclo-rh llvm-toolset-7-clang或者用yumdownloader --resolve把依赖包下载到本地再手动安装:mkdir -p /root/llvm-rpms && cd /root/llvm-rpms yumdownloader --enablerepo=centos-sclo-rh --resolve llvm-toolset-7-clang rpm -Uvh *.rpm这种方法最大的问题在于,一旦离开 yum 仓库解析机制,后续 PostgreSQL 小版本升级时,依赖仍然会断。而且手动rpm -Uvh如果忽略了某个传递依赖,比如没装scl-utils、llvm-toolset-7-libllvm,可能在装完后运行时才报错,排查成本更高。所以我只把它当作临时环境里的应急手段,不建议拿到长期维护的服务器上使用。3.4 三条路径的适用范围对比方案操作难度是否需要额外仓库是否保留 JIT 能力风险点路径 A:补装 SCL 源低需要 SCL 仓库保留仓库维护依赖外部源,但属于标准做法路径 B:源码编译禁 JIT较高不需要不保留脱离包管理,升级靠手动路径 C:手动补 RPM中需要 SCL 仓库且手动指定保留依赖链容易遗漏,应急不长久如果你问我实际会选择哪个,答案基本是路径 A。绝大多数情况下,让 yum 在仓库层面把依赖补齐是最符合 Linux 生态习惯的做法,后续维护成本也最低。4. 装好之后还要注意的几件事:JIT、版本升级和运维习惯4.1 检查 JIT 到底有没有真正生效依赖安装完成、PostgreSQL 启动之后,建议顺手确认一下 JIT 的实际情况。很多朋友以为“装上了就没问题”,其实可以进一步验证。用超级用户连进数据库执行:SELECT name, setting FROM pg_settings WHERE name = 'jit';setting如果是on,说明 JIT 功能处于可用状态。再执行一个稍复杂的查询并打开EXPLAIN:EXPLAIN (ANALYZE, VERBOSE) SELECT count(*), sum(price * quantity) FROM orders WHERE created_at > '2024-01-01' GROUP BY customer_id;输出里如果出现JIT: Functions: 5 Options: Inlining true, Optimization true之类的信息,就说明这个查询确实被 JIT 编译了。如果查询很快就返回,或者完全没有 JIT 字样,也不用担心,PostgreSQL 自己会根据查询代价估估算是否值得用 JIT。如果你的业务以短事务 OLTP 为主,在postgresql.conf里可以关掉 JIT:jit = off需要提醒的是:jit = off只是关闭运行期 JIT 功能,不能解决 RPM 依赖问题。因为二进制文件在编译时已经链接到 LLVM 库,安装层面的 RPM 依赖依然存在,你把llvm-toolset-7-clang卸掉,PostgreSQL 即使不执行 JIT,启动时也可能因为加载不到libLLVM而失败。这一点经常被误解,尤其是一些“既然不用 JIT 就卸载依赖”的操作,很容易把整库搞挂。4.2 大版本升级时,依赖可能会变名字PostgreSQL 的大版本升级,比如从 11 升到 13,往往意味着 JIT 依赖包也会变化。在 CentOS 7 上不同 PGDG 大版本对应的 LLVM 工具集不同,比如 PostgreSQL 12、13 可能依赖llvm-toolset-9-clang或更高版本的工具集,甚至在 RHEL 8 上会改用llvm5.0这类独立包名。这带来的实际影响是:升级之前要先跑一次yum deplist,看清新版本包对 LLVM 的依赖到底落在哪个包上,再对照已启用的仓库检查有没有这个 provider。否则升级画面会重现,只不过包名从llvm-toolset-7-clang变成别的名字。我见过不少搞坏的生产环境,都是因为升级前没看依赖,直接yum update postgresql*,结果新包要求依赖满足不了,数据库版本还停在旧版本上,仓促之间进退两难。4.3 运维习惯:别再依赖“强制忽略依赖”这种操作做系统运维越久,越会觉得rpm --nodeps这种参数应该谨慎使用。在 PostgreSQL 的依赖问题上,--nodeps确实可以让安装跳过检测,但代价是:后续任何用 RPM 解析依赖的工具都可能半瘫痪缺失的库文件直到进程启动时才暴露你无法向审计或同事解释“为什么这个包是这么装进来的”真要给生产服务器装软件,正确的姿势是:先把仓库、订阅、镜像源这些基础设施理顺,再谈具体安装。像这次碰到的llvm-toolset-7-clang,本质上就是一个“仓库基础设施不完整”导致的问题,远不是 PostgreSQL 或者 LLVM 本身的锅。如果你在内网离线环境,仓库基础设施更得多留个心眼:找一台能联网的机器把 SCL 相关 RPM 拉到本地,建一个内部 yum 源,定期同步。这样既解决了依赖,也符合离线交付的合规要求。4.4 新系统上这个问题的形态会不一样如果你已经用上了 CentOS 8、Rocky Linux 8 或者 AlmaLinux 8 这类新系统,同样的报错概率会小很多。因为在 8 系列里,LLVM/Clang 直接以llvm、clang包的形式存在于系统仓库中,dnf install llvm clang就能解决,不需要软件集这个概念。PGDG 在 RHEL 8/Rocky 8 上的 PostgreSQL 13 依赖通常也会落到更直接的 LLVM 包上。但这不代表新系统完全没坑。RHEL 8 开始引入了模块流(AppStream),PostgreSQL 的版本选择比 7 代复杂得多,安装前要确认你选的是 PGDG 源还是 AppStream 内置版本,两者的升级路径和维护方式完全不同。如果从 CentOS 7 迁移到 Rocky Linux 8,还要注意旧数据目录里某些插件和新版本编译选项不一致的问题。这些属于迁移专题,这里不展开,但原则是一样的:先把源和依赖彻底搞明白再动手。我个人的习惯是,在 CentOS/RHEL 系机器上安装任何需要外部依赖的软件时,先花一分钟跑一下yum deplist,再用yum repolist对照检查。很多看着诡异的报错,最后都能归结到“仓库没配齐”这一句上。下次你再看到Requires: llvm-toolset-7-clang >= 4.0.1,就知道该往哪个方向查了。