为什么选择源码编译?
先说说我的立场------我干了十多年运维,大部分生产环境的PostgreSQL我倾向于源码编译,而不是apt install。
原因很简单:包管理器安装的二进制包,编译参数是别人替你定的 。你不知道它有没有开启--with-liburing、有没有链接到你想要的OpenSSL版本、ICU的编译选项对不对。生产环境出问题的时候,这些"未知"会变成排查的盲区。
源码编译虽然多花20分钟,但你能精确控制每一行编译参数,后续排查问题也知道"这个功能我编进去了没有"。------这笔账,我觉得划算。
⚠️ 版本选择 :截至2026年7月,PostgreSQL官方最新稳定版为18.4 ,2026年5月14日发布。18.4是18系列的第四个补丁版本,已修复CVE-2026-6473、CVE-2026-6479、CVE-2026-6476、CVE-2026-6638等多个安全漏洞,稳定性经过充分验证。PostgreSQL 18在I/O层面引入了重大改进------新增io_method配置参数,支持worker(默认)和io_uring两种异步I/O模式,在NVMe存储场景下性能表现优于17系列。本文档基于18.4编写。
前置条件
- 一台Ubuntu 22.04或24.04服务器(物理机或VM均可)
- root权限或sudo权限
- 至少2GB内存(生产环境建议8GB+)
- 至少20GB可用磁盘空间(源码编译+数据目录)
第一步:安装编译依赖
这一步是大多数编译失败的根本原因。我整理了一份生产级完整依赖列表,照着装基本不会缺东西。
sudo apt update
sudo apt install -y \
build-essential \
bison \
flex \
git \
pkg-config \
libreadline-dev \
zlib1g-dev \
libssl-dev \
libicu-dev \
libxml2-dev \
libxslt-dev \
liblz4-dev \
libzstd-dev \
libkrb5-dev \
python3-dev \
libperl-dev \
libsystemd-dev \
liburing-dev \
gettext
逐个解释一下这些包是干嘛的(方便你按需裁剪):
|-----------------------------|---------------------------------------|--------|
| 包名 | 用途 | 是否必须 |
| build-essential | gcc/make等编译工具链 | ✅ 必须 |
| bison、flex | 语法解析器生成 | ✅ 必须 |
| libreadline-dev | psql命令行历史/编辑功能 | ✅ 必须 |
| zlib1g-dev | 压缩支持 | ✅ 必须 |
| libssl-dev | OpenSSL加密(SSL连接) | ⭐ 强烈推荐 |
| libicu-dev | ICU国际化支持(排序/字符集) | ⭐ 强烈推荐 |
| libxml2-dev、libxslt-dev | XML支持(部分扩展需要) | 按需 |
| liblz4-dev、libzstd-dev | 高级压缩算法 | 按需 |
| libsystemd-dev | systemd集成(日志/服务管理) | 推荐 |
| liburing-dev | io_uring异步I/O支持库(对应--with-liburing) | 推荐 |
| libperl-dev | Perl支持(对应--with-perl) | 按需 |
| gettext | 国际化翻译支持(对应--enable-nls) | 按需 |
💡 踩坑提醒 :libicu-dev这个包经常被忽略。如果你./configure时报错说ICU找不到,就是没装它。PG 18中ICU是默认开启的,缺了这个直接编不过。
第二步:下载源码与编译配置
# 创建专用用户(生产环境强烈建议)
sudo adduser --system --group --home /var/lib/postgresql postgres
# 下载源码(从官方镜像站)
cd /usr/local/src
sudo wget https://ftp.postgresql.org/pub/source/v18.4/postgresql-18.4.tar.gz
sudo tar -xzf postgresql-18.4.tar.gz
cd postgresql-18.4
# 配置编译选项(生产级配置)
./configure \
--prefix=/usr/local/postgresql/18.4 \
--with-pgport=5432 \
--with-openssl \
--with-icu \
--with-libxml \
--with-libxslt \
--with-lz4 \
--with-zstd \
--with-systemd \
--with-liburing \
--with-perl \
--with-python \
--enable-nls
各参数说明:
--prefix:安装目录,我习惯按版本号区分,方便日后多版本共存或升级回滚--with-pgport:默认端口,生产环境如果有多个PG实例可以在这里改--with-openssl:开启SSL加密连接--with-icu:开启ICU国际化支持--with-lz4/--with-zstd:开启高级压缩--with-systemd:生成systemd服务文件--with-liburing:开启io_uring支持,需链接liburing库(PG 18的核心性能特性之一)--with-perl:开启Perl支持(对应依赖libperl-dev)--enable-nls:开启国际化支持(对应依赖gettext)
💡 PG 18编译选项变更说明 :PG 18中io_uring的编译选项为--with-liburing(早期开发版曾用--with-uring,后更名为--with-io-uring,最终正式版确定为--with-liburing)。另外--enable-thread-safety在PG 18中已是默认行为,无需再显式指定。
执行后会滚动输出大量checking...信息。只要最后没有出现 error: ...字样,且执行 echo $?返回 0,就说明配置通过了。
预期输出(配置成功时的末尾部分):
configure: using compiler=gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0
configure: using CFLAGS=-Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wimplicit-fallthrough=3 -Wcast-function-type -Wshadow=compatible-local -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -Wno-format-truncation -Wno-stringop-truncation -O2
configure: using CPPFLAGS= -D_GNU_SOURCE -I/usr/include/libxml2
configure: using LDFLAGS= -Wl,--as-needed
configure: creating ./config.status
config.status: creating GNUmakefile
config.status: creating src/Makefile.global
config.status: creating src/include/pg_config.h
config.status: creating src/interfaces/ecpg/include/ecpg_config.h
config.status: linking src/backend/port/tas/dummy.s to src/backend/port/tas.s
config.status: linking src/backend/port/posix_sema.c to src/backend/port/pg_sema.c
config.status: linking src/backend/port/sysv_shmem.c to src/backend/port/pg_shmem.c
config.status: linking src/include/port/linux.h to src/include/pg_config_os.h
config.status: linking src/makefiles/Makefile.linux to src/Makefile.port
不再出现 WARNING: unrecognized options------说明所有参数都正确识别了。
第三步:编译与安装
# 编译主程序(-j后面的数字是CPU核心数,我一般用nproc)
make -j$(nproc)
# 编译所有附加模块(contrib)
make world-bin -j$(nproc)
# 安装
sudo make install
sudo make install-world-bin
make world-bin会编译包括contrib目录下所有扩展模块(pg_stat_statements、pgcrypto等),但不包含文档。生产环境我一般不编文档,省时间。
编译时间取决于机器配置,我曾在8核机器上跑过,大概8-12分钟。
第四步:内核参数调优
这一步我习惯在初始化数据库之前做。内核参数修改后需要sysctl -p生效,且它影响的是OS内存分配,不依赖PG的配置文件,放在这里顺理成章。
编辑/etc/sysctl.conf,追加以下内容:
# 共享内存(PostgreSQL使用System V共享内存)
kernel.shmmax = 68719476736 # 64GB,物理≥64GB时适用;物理32GB则改为34359738368
kernel.shmall = 16777216 # shmmax值 / 4096(页面大小),需同步调整
# 网络优化
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
# 内存交换倾向(生产环境强烈建议调低)
vm.swappiness = 10
⚠️ 注意 :kernel.shmmax建议设置为物理内存大小的80%~100% ,但至少大于shared_buffers。示例中的64GB适用于物理内存≥64GB的服务器。kernel.shmall需同步调整,计算方式为shmmax值除以4096(页面大小),例如物理32GB时,shmmax=34359738368,shmall=34359738368/4096=8388608。PG 18官方文档指出,现代Linux系统通常已默认允许所有内存作为共享内存使用,无需特殊配置------但显式设置仍是一种良好的习惯。
生效:
sudo sysctl -p
第五步:初始化数据库与设置密码
# 创建数据目录(建议放在独立数据盘)
sudo mkdir -p /data/postgresql/18.4
sudo chown postgres:postgres /data/postgresql/18.4
sudo chmod 700 /data/postgresql/18.4
# 切换到postgres用户初始化
sudo -u postgres /usr/local/postgresql/18.4/bin/initdb \
-D /data/postgresql/18.4 \
-E UTF8 \
--locale=C.UTF-8
# 先以默认方式启动
sudo -u postgres /usr/local/postgresql/18.4/bin/pg_ctl \
-D /data/postgresql/18.4 \
-l /data/postgresql/18.4/logfile \
start
# 确认启动成功后再设置密码
sudo -u postgres /usr/local/postgresql/18.4/bin/pg_ctl -D /data/postgresql/18.4 status
# 预期输出:pg_ctl: server is running (PID: xxxx)
# 设置强密码(请替换 YourStrongP@ssw0rd)
sudo -u postgres /usr/local/postgresql/18.4/bin/psql \
-c "ALTER USER postgres WITH PASSWORD 'YourStrongP_ssw0rd';"
# 停掉临时实例,后续用systemd正常启动
sudo -u postgres /usr/local/postgresql/18.4/bin/pg_ctl \
-D /data/postgresql/18.4 \
stop
预期输出(initdb成功时):
vb
`The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.
The database cluster will be initialized with locale "C.UTF-8".
The default text search configuration will be set to "english".
Data page checksums are disabled.
fixing permissions on existing directory /data/postgresql/18.4 ... ok
creating subdirectories ... ok
selecting dynamic shared memory implementation ... posix
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok
Success. You can now start the database server using:
pg_ctl -D /data/postgresql/18.4 -l logfile start`
第六步:生产环境核心配置调优
编译、初始化、密码都搞定了,但在用systemd启动之前,还有一件最关键的事------配置调优 。默认的配置文件是跑不了生产的,下面这两份配置直接完整替换 原有的postgresql.conf和pg_hba.conf即可。
6.1 postgresql.conf核心参数(完整替换文件)
操作方式 :直接用下面的内容覆盖 /data/postgresql/18.4/postgresql.conf。
# 备份原配置(可选但推荐)
sudo cp /data/postgresql/18.4/postgresql.conf /data/postgresql/18.4/postgresql.conf.bak
sudo tee /data/postgresql/18.4/postgresql.conf > /dev/null <<'EOF'
# ==================== 连接与并发 ====================
listen_addresses = '0.0.0.0' # 生产环境改为具体IP
port = 5432
max_connections = 200 # 根据应用并发调整
# ==================== 内存(假设物理内存32GB) ====================
shared_buffers = 8GB # 系统内存的25%
work_mem = 64MB # 每个排序/哈希操作可用内存
maintenance_work_mem = 2GB # VACUUM/CREATE INDEX等维护操作
effective_cache_size = 24GB # 系统内存的75%(OS缓存预估)
# ==================== I/O(PG 18新增重要参数) ====================
io_method = 'worker' # 默认值,使用专用后台进程处理I/O
# io_method = 'io_uring' # 如使用Linux 5.1+内核且存储为NVMe,可开启此选项获得更好性能
# io_method = 'sync' # 同步I/O,与17及更早版本行为一致
# ==================== WAL与检查点 ====================
wal_buffers = 64MB
checkpoint_timeout = 15min
max_wal_size = 20GB
min_wal_size = 4GB
# ==================== 查询优化 ====================
effective_io_concurrency = 200 # SSD设为200,HDD设为2
random_page_cost = 1.1 # SSD设为1.1,HDD设为4
# ==================== 日志(排错必备) ====================
logging_collector = on
log_directory = 'pg_log'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_min_duration_statement = 5000 # 记录超过5秒的慢查询
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
log_checkpoints = on
log_connections = on
log_disconnections = on
# ==================== 统计信息(pg_stat_statements需要) ====================
shared_preload_libraries = 'pg_stat_statements'
pg_stat_statements.max = 10000
pg_stat_statements.track = all
EOF
# 设置正确权限
sudo chown postgres:postgres /data/postgresql/18.4/postgresql.conf
💡 PG 18的 io_method新特性 :PostgreSQL 18引入了io_method配置参数,允许你控制磁盘I/O的处理方式。worker(默认)使用专用后台进程处理所有I/O操作;io_uring利用Linux io_uring接口实现异步磁盘读取,在NVMe存储场景下性能提升显著。如果服务器使用NVMe SSD且内核版本≥5.1,可以取消注释io_method = 'io_uring'(将默认的worker注释掉)。但需要注意,io_uring的改进主要针对读取操作,对写入密集型工作负载影响较小。
💡 shared_buffers的玄学 :官方文档和社区公认的推荐值是系统内存的25%。我见过有人设到80%结果把系统搞崩了------PostgreSQL的shared_buffers是独立于OS页缓存的,设太高会导致双缓存浪费,反而降低性能。
6.2 pg_hba.conf安全配置(完整替换文件)
操作方式 :直接用下面的内容覆盖 /data/postgresql/18.4/pg_hba.conf。默认配置中包含了大量注释和示例,直接覆盖最干净,不会造成配置混乱。
# 备份原配置(可选但推荐)
sudo cp /data/postgresql/18.4/pg_hba.conf /data/postgresql/18.4/pg_hba.conf.bak
sudo tee /data/postgresql/18.4/pg_hba.conf > /dev/null <<'EOF'
# PostgreSQL Client Authentication Configuration File
# ===================================================
# 本地连接(Unix socket)
local all postgres peer # postgres用户本地socket免密(方便管理员)
local all all scram-sha-256
# 主机连接(生产环境限制具体IP段)
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
host all all 192.168.0.0/16 scram-sha-256 # ⚠️ 请替换为实际内网网段
# 默认拒绝所有其他连接(安全兜底)
host all all 0.0.0.0/0 reject
host all all ::0/0 reject
EOF
# 设置正确权限
sudo chown postgres:postgres /data/postgresql/18.4/pg_hba.conf
为什么postgres用户不用输密码? 这条peer规则是故意保留的------你用postgres用户在服务器本地执行psql时不需要密码,方便运维操作。但其他用户和远程连接都必须走scram-sha-256密码认证,安全不受影响。生产环境如果对安全有极致要求,也可以把peer改成scram-sha-256,但需要确保你记得密码。
⚠️ 安全提醒 :示例中的192.168.0.0/16是占位网段,请根据你的实际内网IP规划修改(例如10.0.0.0/8或172.16.0.0/12)。最后的reject规则是安全兜底,确保未明确允许的连接全部被拒绝。
第七步:配置systemd开机自启
配置文件和密码都已就绪,现在可以启动并设置开机自启了。
编译时加了--with-systemd,会在源码包的contrib/start-scripts/linux/目录下生成postgresql.service模板文件。你可以手动复制到系统目录,也可以直接用下面我提供的配置文件(两种方式等效):
# 方式一:复制编译生成的模板文件
sudo cp /usr/local/src/postgresql-18.4/contrib/start-scripts/linux/postgresql.service /etc/systemd/system/postgresql-18.4.service
# 方式二:如果模板不存在或你想自定义,手动创建该文件(内容见下方)
如果选择手动创建,将以下内容写入/etc/systemd/system/postgresql-18.4.service:
[Unit]
Description=PostgreSQL 18.4 database server
After=network.target
[Service]
Type=forking
User=postgres
Group=postgres
Environment=PGDATA=/data/postgresql/18.4
OOMScoreAdjust=-1000
ExecStart=/usr/local/postgresql/18.4/bin/pg_ctl start -D ${PGDATA} -s -w -t 300
ExecStop=/usr/local/postgresql/18.4/bin/pg_ctl stop -D ${PGDATA} -s -m fast
ExecReload=/usr/local/postgresql/18.4/bin/pg_ctl reload -D ${PGDATA} -s
TimeoutSec=300
[Install]
WantedBy=multi-user.target
创建好服务文件后,启用并启动:
sudo systemctl daemon-reload
sudo systemctl enable postgresql-18.4
sudo systemctl start postgresql-18.4
验证方法
# 1. 使用pg_ctl检查服务状态(比ps更可靠)
sudo -u postgres /usr/local/postgresql/18.4/bin/pg_ctl -D /data/postgresql/18.4 status
# 预期输出:pg_ctl: server is running (PID: xxxx)
# 2. 检查进程
ps aux | grep postgres
# 3. 连接测试(必须用 sudo -u postgres,否则会触发 peer 认证失败)
sudo -u postgres /usr/local/postgresql/18.4/bin/psql -d postgres -c "SELECT version();"
# 预期输出:
# PostgreSQL 18.4 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, 64-bit
# 4. 检查配置参数
sudo -u postgres /usr/local/postgresql/18.4/bin/psql -d postgres -c "SHOW shared_buffers;"
# 预期输出:8GB
# 5. 检查io_method参数(PG 18新增)
sudo -u postgres /usr/local/postgresql/18.4/bin/psql -d postgres -c "SHOW io_method;"
# 预期输出:worker(或io_uring,取决于你的配置)
# 6. 检查log_line_prefix是否生效
sudo -u postgres /usr/local/postgresql/18.4/bin/psql -d postgres -c "SHOW log_line_prefix;"
# 预期输出:%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h
# 7. 创建并验证pg_stat_statements扩展
sudo -u postgres /usr/local/postgresql/18.4/bin/psql -d postgres -c "CREATE EXTENSION IF NOT EXISTS pg_stat_statements;"
# 执行一条测试查询,确保有数据被记录
sudo -u postgres /usr/local/postgresql/18.4/bin/psql -d postgres -c "SELECT 1;"
# 验证pg_stat_statements是否正常记录
sudo -u postgres /usr/local/postgresql/18.4/bin/psql -d postgres -c "SELECT query, calls FROM pg_stat_statements LIMIT 3;"
预期输出(第7步最后一条查询):
query | calls
-----------+-------
SELECT 1; | 1
(1 row)
💡 为什么所有 psql 命令都要加 sudo -u postgres? 因为 pg_hba.conf 中配置了 local all postgres peer,peer 认证要求操作系统用户名必须与数据库用户名一致。用 postgres 系统用户执行命令就能免密登录,用 root 则会报 Peer authentication failed。这也是生产环境的安全设计------强制运维人员用 postgres 用户操作数据库,避免误用 root 权限。
常见问题(含真实报错)
❌ 问题1:ICU库找不到
真实报错原文(来源:社区博客):
configure: error: ICU library not found
解决方案:
sudo apt install libicu-dev
# 或者如果不需要ICU支持,可以加 --without-icu 跳过
./configure --without-icu ...
❌ 问题2:readline库未找到
真实报错原文(来源:PostgreSQL官方邮件列表):
configure: error: readline library not found
解决方案:
sudo apt install libreadline-dev
❌ 问题3:编译时locale报错
真实报错原文(来源:PostgreSQL官方文档):
Building might fail on some systems where a locale other than C is in use.
解决方案(官方推荐):
export LANG=C.utf8
./configure ...
# 编译完成后再恢复
❌ 问题4:make world失败,提示bison/flex版本过低
解决方案:
sudo apt install bison flex
# 检查版本
bison --version # 需要3.0+
❌ 问题5:启动时端口被占用
真实报错:
FATAL: could not bind to address 0.0.0.0:5432: Address already in use
解决方案:
# 检查占用进程
sudo netstat -tlnp | grep 5432
# 修改postgresql.conf中的port,或停止原有PG实例
❌ 问题6:设置密码后仍无法登录
真实报错:
FATAL: password authentication failed for user "postgres"
原因 :pg_hba.conf中认证方式配置为scram-sha-256,但密码未正确设置,或客户端不支持scram-sha-256。
解决方案:
# 确认密码已设置
sudo -u postgres /usr/local/postgresql/18.4/bin/psql -c "SELECT rolpassword IS NOT NULL FROM pg_authid WHERE rolname='postgres';"
# 如果返回f,重新设置密码
sudo -u postgres /usr/local/postgresql/18.4/bin/psql -c "ALTER USER postgres WITH PASSWORD 'YourStrongP@ssw0rd';"
❌ 问题7:以 root 用户执行 psql 时报错 Peer authentication failed
真实报错原文(实测复现):
psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed: FATAL: Peer authentication failed for user "postgres"
原因 :pg_hba.conf 中配置了 local all postgres peer,peer 认证要求操作系统用户名(如 root)必须与数据库用户名(postgres)一致,否则拒绝连接。
解决方案(二选一):
# 方案一:切换为 postgres 系统用户执行(推荐)
sudo -u postgres /usr/local/postgresql/18.4/bin/psql -d postgres
# 方案二:改用 TCP/IP 连接,强制走密码认证
/usr/local/postgresql/18.4/bin/psql -U postgres -d postgres -h 127.0.0.1
# 然后输入第五步设置的 postgres 密码
💡 这不是配置错误 ,而是 peer 认证的安全设计。生产环境建议始终使用 sudo -u postgres 或 su - postgres 切换用户后再执行 psql,避免误用 root 权限操作数据库。
总结
从头到尾捋一遍核心要点:
- 版本选择:18.4是18系列的第四个补丁版本,2026年5月14日发布,已修复多个CVE漏洞,稳定性经过充分验证。
- PG 18核心新特性 :新增
io_method参数,支持worker(默认)和io_uring两种异步I/O模式,NVMe场景下性能优于17系列。 - 编译选项关键变更 :PG 18中io_uring的编译选项为
--with-liburing(非--with-uring或--with-io-uring),--enable-thread-safety已不再需要。 - 依赖安装 :
libicu-dev、libreadline-dev、libssl-dev、libperl-dev、gettext这五个最容易漏,漏了直接编不过。 - 配置文件替换 :第六步的
postgresql.conf和pg_hba.conf已提供完整可替换文件,直接覆盖即可,无需手动逐行修改。 - 密码设置 :initdb之后务必 设置postgres密码,否则
pg_hba.conf的scram-sha-256认证会卡死你。 peer认证注意 :执行psql时必须用sudo -u postgres切换到postgres系统用户,否则会触发Peer authentication failed。这不是错误,是安全设计。- 调优时机 :在第一次systemd启动之前就把
postgresql.conf调好,一次到位,省得反复重启。
如果觉得有用,欢迎分享给更多同行。有问题欢迎在评论区交流------你生产环境踩过什么PG的坑?一起聊聊。
参考来源: