Published on

现代化的方式编译安装 PostgreSQL

Authors

很早之前写过 POSTGRESQL 的编译安装及配置,现在有些内容可以优化一下。

安装编译依赖的部分基本不变:

yum -y install lrasz sysstat e4fsprogs ntp readline-devel zlib zlib-devel openssl openssl-devel pam-devel libxml2-devel libxslt-devel python-devel tcl-devel gcc make smartmontools flex bison perl perl-devel perl-ExtUtils* openIPMI-tools systemtap-sdt-devel openldap openldap-devel

修改内核参数

kernel.shmmni = 4096
kernel.sem = 50100 64128000 50100 1280
fs.file-max = 7672460
net.ipv4.ip_local_port_range = 9000 65000
net.core.rmem_default = 1048576
net.core.rmem_max = 4194304
net.core.wmem_default = 262144
net.core.wmem_max = 1048576
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_max_syn_backlog = 4096
net.core.netdev_max_backlog = 10000
vm.overcommit_memory = 0
fs.aio-max-nr = 1048576
net.ipv4.tcp_timestamps = 0

上面的配置多数是合理的,有两项特别说明,net.ipv4.tcp_tw_recycle = 0 原来是 1,这里改为 0。此参数在内核 4.12 以后被废弃,因为它在 NAT 环境中可能引起问题。建议设置为 0 以避免潜在问题。

具体来说,tcp_tw_recycle 参数的作用是加速 TIME_WAIT 状态的 TCP 连接的回收,从而减少系统中处于 TIME_WAIT 状态的连接数量。但是,该机制依赖于 TCP 时间戳的快速重用。在启用 tcp_tw_recycle 的情况下,当一个新的 TCP 连接使用了先前处于 TIME_WAIT 状态的连接的相同四元组(源IP、源端口、目标IP、目标端口)时,内核会通过时间戳判断是否可以快速回收这个连接。

然而,这在 NAT 环境中会引发问题。NAT(网络地址转换)会让多个设备共享一个公共 IP 地址。当 tcp_tw_recycle 启用时,来自不同设备的 TCP 连接会被认为是同一个连接,因为它们使用了相同的公共 IP 地址和端口组合,并且时间戳也可能存在冲突。这会导致连接被错误地快速回收,从而引起以下问题:

  1. 连接复用问题:多个设备通过 NAT 共享一个公共 IP,可能会导致时间戳冲突,使得新的连接被误认为是老的连接,从而导致连接复用失败。
  2. 连接不稳定:快速回收机制在时间戳冲突的情况下会导致连接不稳定,数据包丢失或连接重置。
  3. NAT 环境中的问题:在使用 NAT 的环境中,比如家庭路由器、公司网络、云环境等,多个客户端设备共享一个公共 IP 地址,这种机制会导致连接管理混乱。

因此,启用 tcp_tw_recycle 会导致 NAT 环境中的 TCP 连接出现问题。为了解决这个问题,Linux 内核开发者决定在 4.12 版本以后弃用这个参数,以避免上述问题。

建议在所有现代系统中都将 net.ipv4.tcp_tw_recycle 设置为 0,以确保 TCP 连接的稳定性,特别是在 NAT 环境中运行的应用程序和服务器。

还有一项:net.ipv4.tcp_timestamps = 0,禁用 TCP 时间戳可以减少 TCP 包的开销,提高性能。

禁用 TCP 时间戳 (net.ipv4.tcp_timestamps=0) 可以提高性能的原因主要有以下几个方面:

1.  减少包头开销:
TCP 时间戳选项在每个 TCP 报文段中增加 12 个字节的开销。这些字节包括 4 字节的时间戳值和 4 字节的回显回复,以及 4 字节的选项类型和长度字段。禁用时间戳选项可以减小每个 TCP 报文段的大小,从而减少传输的总数据量,特别是在高并发和高吞吐量的网络环境中,这种减少可能会对性能产生显著影响。
2.  降低处理复杂性:
•   启用 TCP 时间戳意味着内核需要在每个报文段中生成、附加、解析和验证时间戳。这些额外的操作会增加 CPU 的处理负担。禁用时间戳可以减少这些额外的计算开销,从而降低 CPU 使用率,提高系统的总体性能。
3.  减少缓存压力:
TCP 时间戳的使用需要维护每个连接的时间戳信息,禁用时间戳可以减少内核中维护这些状态信息的开销,从而降低缓存和内存的压力。

然而,禁用 TCP 时间戳也有其潜在的缺点,特别是在高延迟或不稳定的网络环境中:

•   丢包恢复效率降低:TCP 时间戳有助于更准确地检测网络中的包重传和丢包情况,禁用它可能会影响这些机制的效率。
•   保护机制缺失:TCP 时间戳可以防止序列号的包重放攻击,提高连接的安全性,禁用时间戳会失去这种保护。

因此,是否禁用 TCP 时间戳应根据具体应用场景和网络环境权衡。如果你的系统在低延迟、可靠的网络环境中运行,并且性能优化是主要目标,可以考虑禁用 TCP 时间戳。如果你运行在高延迟、不稳定的网络环境中,或者需要更高的安全性和丢包恢复能力,建议保持启用。

在编译安装 PostgreSQL 时,可以使用一些现代 CPU 优化指令来提高性能。这些优化指令通常由编译器选项控制。一些新的编译选项:

GCC 编译器优化选项

基本优化选项

-O2-O3:这些选项启用不同级别的优化,-O3 通常会生成更快的代码,但也可能会增加编译时间和生成更大的二进制文件。
-march=native:这个选项会根据编译时使用的 CPU 生成优化指令,自动启用该 CPU 支持的所有指令集扩展。

具体 CPU 优化指令

-msse4.2:启用 SSE4.2 指令集优化。
-mavx:启用 AVX 指令集优化。
-mavx2:启用 AVX2 指令集优化。
-mfma:启用 FMA (Fused Multiply-Add) 指令集优化。
-m64:生成 64 位代码。
-funroll-loops:展开循环,可以提高某些计算密集型任务的性能。

其他考虑因素

LTO (Link Time Optimization):链接时优化可以进一步提高性能。可以在配置时添加 --enable-lto 选项。
•   并行编译:使用 make -j 选项进行并行编译,可以加快编译速度,-j 后跟的数字指定并行编译的线程数,通常设为 CPU 核心数。
•   配置特定于 PostgreSQL 的选项:在 configure 阶段,可以添加一些 PostgreSQL 特定的配置选项,如 --with-openssl、--with-libxml、--with-libxslt 等。

具体编译命令如下:

wget https://ftp.postgresql.org/pub/source/v16.3/postgresql-16.3.tar.bz2
tar xf postgresql-16.3.tar.bz2
cd postgresql-16.3
./configure \
  --prefix=/usr/local/pgsql \
  --enable-lto \
  --with-openssl \
  --with-libxml \
  --with-libxslt \
  --with-perl \
  --with-python \
  CFLAGS="-O3 -march=native -funroll-loops" \
  LDFLAGS="-L/usr/local/lib" \
  CPPFLAGS="-I/usr/local/include"

重点说下 --enable-lto 这个选项:--enable-lto 是配置编译时使用的一个选项,用来启用链接时优化 (Link Time Optimization, LTO)。LTO 是一种高级的优化技术,允许编译器在链接阶段执行跨模块优化,从而生成更高效的代码。

链接时优化是一种编译器优化技术,它允许编译器在链接阶段进行全程序优化,而不仅仅是在每个单独的编译单元内进行优化。这意味着编译器可以看到程序的全局视图,并进行跨模块的优化,例如函数内联、移除冗余代码和更高效的寄存器分配等。

使用 --enable-lto 的好处

  1. 提高性能:通过跨模块优化,LTO 可以生成更高效的机器代码,提高程序的运行性能。
  2. 减少代码大小:通过消除冗余代码和更高效的优化,LTO 可以减少生成的二进制文件的大小。
  3. 全局优化:LTO 允许编译器进行全局范围的优化,而不仅仅局限于单个源文件的优化。
make -j$(nproc) world
sudo make install-world