PostgreSQL 9.6.21迁移至RHEL7新基础设施后性能下降的原因分析及本地性能恢复方案咨询
这是个很典型的跨RHEL版本迁移后的PostgreSQL性能问题——你已经排除了存储、网络、架构(测试在异步从库)这些常见变量,甚至用本地磁盘验证了存储层无影响,那核心差异就聚焦在RHEL7与RHEL6的系统底层差异以及PostgreSQL在新系统上的适配性上。结合你给出的测试数据(简单select version()的规划/执行时间翻倍),我来拆解可能的原因和对应的修复手段:
可能的性能瓶颈原因
1. glibc版本差异导致的底层开销
RHEL6使用glibc 2.12,而RHEL7升级到了glibc 2.17。PostgreSQL 9.6.21如果是基于RHEL6编译的二进制,直接放到RHEL7上运行时,glibc的内存分配(malloc)、系统调用封装等底层行为会有变化:
- 新版glibc的内存分配器默认会为每个CPU核心创建独立的分配arena,在高并发场景下能提升性能,但对于低负载的简单查询,反而会增加初始化和管理开销;
- 某些底层函数的实现逻辑调整,导致PostgreSQL的查询规划器、执行器的基础调用开销上升。
2. NUMA架构的默认适配问题
RHEL7对NUMA(非统一内存访问)的默认处理逻辑和RHEL6不同。如果你的服务器是NUMA架构,PostgreSQL默认不会绑定到特定的NUMA节点,跨节点内存访问的延迟会比同节点高很多——哪怕总内存足够,也会影响简单查询的响应时间。
3. 内核调度与安全特性的额外开销
RHEL7默认开启了更多的安全特性(比如SELinux的默认策略更严格),同时CFS调度器的默认参数也和RHEL6的调度器有差异:
- SELinux的强制模式可能会对PostgreSQL的文件访问、进程操作增加额外的权限检查开销;
- 内核的进程调度优先级、CPU亲和性默认设置,可能导致PostgreSQL进程无法稳定占用核心资源。
4. 跨系统二进制的兼容性损耗
如果你的PostgreSQL是直接从RHEL6拷贝过来的二进制文件,而不是在RHEL7上重新编译的,那么编译时的依赖库、优化选项都是针对RHEL6的,在RHEL7上运行时会有兼容性层的额外开销,尤其是底层的指令集、系统调用适配部分。
恢复本地性能的实操手段
1. 针对RHEL7重新编译PostgreSQL
这是最有效的适配手段,能让PostgreSQL完全利用RHEL7的系统特性:
- 下载PostgreSQL 9.6.21的源码包,安装编译依赖:
yum install gcc make readline-devel zlib-devel openssl-devel; - 配置编译选项(优化性能并适配NUMA):
./configure --prefix=/usr/local/pgsql --enable-optimized --with-numa --with-openssl - 编译安装:
make && make install,然后迁移数据和配置文件,重启服务。
2. 调整内核与系统参数
(1)优化NUMA绑定
用numactl --hardware查看服务器的NUMA节点信息,然后修改PostgreSQL的启动命令,绑定到同一个NUMA节点:
numactl --cpunodebind=0 --membind=0 /usr/local/pgsql/bin/postgres -D /var/lib/pgsql/data
如果用systemd管理服务,可以在postgres.service文件中添加:
ExecStartPre=/usr/bin/numactl --cpunodebind=0 --membind=0
(2)限制glibc内存分配arena数量
在PostgreSQL的启动环境中添加MALLOC_ARENA_MAX=1,避免多arena带来的开销:
- 如果是systemd服务,在
postgres.service的[Service]段添加:Environment=MALLOC_ARENA_MAX=1 - 重启服务后测试性能变化。
(3)调整内存与调度参数
- 设置
vm.swappiness=10(编辑/etc/sysctl.conf,执行sysctl -p生效),减少系统swap的使用; - 临时关闭SELinux测试:
setenforce 0,如果性能提升,再通过semanage配置PostgreSQL的SELinux规则,而非直接关闭; - 提升PostgreSQL进程的优先级:
renice -10 $(pgrep postgres),或者在systemd服务中配置Nice=-10。
3. 验证大页配置有效性
虽然你说大页配置相同,但RHEL7的大页生效条件略有不同:
- 确认
vm.nr_hugepages设置正确(编辑/etc/sysctl.conf); - 检查postgres用户的内存锁定限制:在
/etc/security/limits.conf中添加:postgres soft memlock unlimited postgres hard memlock unlimited - 重启PostgreSQL后,用
grep HugePages /proc/meminfo查看大页使用情况,确认PostgreSQL在使用大页。
4. 用perf工具精准定位瓶颈
如果以上手段还没解决问题,用perf工具分析具体的CPU开销:
- 实时查看进程的函数开销:
perf top -p $(pgrep postgres); - 记录并分析调用栈:
perf record -g -p $(pgrep postgres) perf report
通过这些信息可以精准定位是哪个函数或系统调用导致的性能损耗,再针对性优化。
内容的提问来源于stack exchange,提问作者Aspha

