项目组最近把一套业务系统从旧环境迁到 Ubuntu 24.04 上,数据库选型定的是 PostgreSQL 18。这个版本是 2025 年 9 月发布的新稳定版,在并行查询、内存管理、逻辑复制上有不少改进,安装方式和旧版本也有细微差别。我们把整个过程从头跑了一遍:安装 PostgreSQL18、配置远程连接、补常用插件、做性能调优。这篇实操记录适合要在 Ubuntu 24.04 上快速部署 PG18 的开发、运维和全栈同学,照着做基本能避开一半的坑。
写之前先把结论放前面:PostgreSQL 18 在 Ubuntu 24.04 上完全可以走官方 apt 仓库安装,不建议编译安装;远程连接失败 90% 是三个原因——监听地址没改、pg_hba.conf 没加规则、云服务器安全组没放行 5432 端口;性能调优别一上来就改 shared_buffers,先把监控插件和数据基线建起来再说。下面按实际部署顺序展开。
1. 安装前的思路:选型与准备工作
1.1 为什么选 PostgreSQL 18
PostgreSQL 18 是 2025 年 9 月发布的大版本,按照官方惯例,这个版本进入稳定维护期,适合生产部署。相比十七代,它有几点值得关注:并行顺序扫描在方向感知上做了优化,对全表扫描场景更友好;增量排序的执行效率有提升;逻辑复制支持了更灵活的表同步方式。不过这些特性对日常使用来说更多是“感觉更快了”,真正影响部署决策的是版本生命周期——新装环境没必要选一个快接近 EOL 的旧版本,直接从 18 起步是划算的。
我见过很多团队在版本选择上犹豫,最后装了个系统自带的老版本。Ubuntu 24.04 官方源里的 PostgreSQL 版本是 16,如果你直接 apt install postgresql,装出来的是 PG16,不是 18。对已有业务迁移来说这有很大区别,比如某些新语法、JSONB 操作符、并行查询策略在 16 和 18 之间是有差距的。既然标题都写了 18,这一步就得通过官方 PostgreSQL apt 仓库来安装。
1.2 安装方式选型:用官方仓库而不是编译源码
PostgreSQL 的传统安装方式有三种:系统自带源、编译源码、官方 apt 仓库。系统自带源的问题是版本偏旧,编译源码的问题是升级和维护成本高。我最推荐的是第三种方式——安装 postgresql-common 工具包后,通过官方脚本自动配置 PG 专用 apt 源。
编译安装唯一明显的好处是能自定义编译参数,比如按 CPU 指令集优化。但对于绝大多数场景,这个收益根本抵不过后续升级的痛苦。你想想,源码编译的 PostgreSQL 出了安全更新,你得重新 configure、make、make install,然后还要处理数据目录、配置文件的兼容性。用官方 apt 仓库,一条 apt install 就能搞定版本升级,还能自动处理系统服务,这才是正经运维该走的路线。
还有个细节要注意:PostgreSQL 的 apt 仓库地址是按 Ubuntu 发行代号区分的,Ubuntu 24.04 对应的是 noble。这个代号错了,源会解析失败。官方脚本会自动识别,这也是我推荐用脚本的原因。
1.3 安装 PostgreSQL 18 并完成初始化验证
先安装 postgresql-common 和官方源配置脚本,然后运行它:
sudo apt-get update sudo apt-get install -y postgresql-common sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh运行脚本后会让你选择要安装的版本,输入 18 并确认添加源。脚本执行完,再刷新一次软件源,安装 PostgreSQL 18:
sudo apt-get update sudo apt-get install -y postgresql-18安装完成后,验证状态和版本:
systemctl status postgresql@18-main.service psql --version正常情况下你会看到 postgresql@18-main 服务处于 active (running) 状态,psql --version 输出为 psql (PostgreSQL) 18.x。数据目录在 /var/lib/postgresql/18/main,配置文件在 /etc/postgresql/18/main,日志在 /var/log/postgresql/postgresql-18-main.log。这些路径后面排错会用上,建议记一下。
安装完 PostgreSQL 之后,系统会自动创建一个 postgres 系统用户。你要进入数据库命令行,在 Ubuntu 终端下执行:
sudo -u postgres psql这一步能通,说明安装没问题。接下来进入正题:设置密码和配置远程连接。注意,刚安装好的 PostgreSQL 默认只允许本机访问,外部根本连不上,这是安全的默认策略,不要觉得是自己装坏了。
2. 远程连接配置:打通三个关卡
2.1 搞清楚连接链路:监听、认证、防火墙
PostgreSQL 远程连不上,绝大多数情况不是数据库坏了,而是链路里有某道关卡没放行。整个链路可以理解成三层:
第一层是数据库监听。postgresql.conf 里的 listen_addresses 决定 PostgreSQL 监听哪些网卡地址。默认值是 localhost,意思是只监听本机回环地址,外部机器即使网络通,也会被拒绝连接。第二层是访问认证,pg_hba.conf 决定哪些 IP 网段用哪种方式认证。这一层容易出两种错:没有匹配的规则,或者认证方式对不上。第三层是操作系统防火墙和云安全组。Ubuntu 自带 ufw,云服务器还有独立的安全组规则,这两处任何一处没放行 5432 端口,外部连接就会卡住。
很多人只改了 postgresql.conf,却发现本机连得上、外部连不上,就是因为忽略了其它两层。正确做法是把这三层逐一确认。
2.2 一步步配置远程连接
先给 postgres 用户设置强密码,进入 psql 后执行:
ALTER USER postgres PASSWORD '你的强密码';PostgreSQL 14 之后默认的密码加密方式是 scram-sha-256,18 依旧如此。这个细节很重要,如果你在 pg_hba.conf 里写的认证方式和实际密码加密方式不匹配,会出现认证失败。不用刻意改 password_encryption,保持默认的 scram-sha-256 就好。
然后修改监听地址,编辑 /etc/postgresql/18/main/postgresql.conf:
listen_addresses = '*'生产环境不建议无脑用通配符。如果你知道应用服务器的固定 IP,最好写具体 IP 或用逗号分隔多个 IP,例如 listen_addresses = 'localhost,192.168.1.10'。如果是在云环境内网部署,建议监听内网 IP,避免数据库端口暴露到公网。修改之后重启服务:
sudo systemctl restart postgresql@18-main接下来修改 pg_hba.conf。文件在 /etc/postgresql/18/main/pg_hba.conf。建议在文件末尾追加规则,用具体网段代替全网段:
host all all 192.168.1.0/24 scram-sha-256这里解释一下格式:host 表示 TCP/IP 连接,all all 表示所有数据库和所有用户,192.168.1.0/24 是允许访问的网段,scram-sha-256 是认证方式。如果你只想让某一个 IP 连接,可以写成 100.100.100.10/32。改完不需要重启,执行 reload 即可生效:
sudo systemctl reload postgresql@18-main还有防火墙。Ubuntu 的 ufw 放行命令:
sudo ufw allow 5432/tcp如果你用的是云服务器,还要在云厂商控制台的安全组里,添加入方向规则,放行 TCP 5432 端口。这一步最容易漏,因为本机连数据库、局域网内一台机器连数据库都正常,但公网 IP 访问就报连接超时,十有八九是安全组没放行。
最后在外部机器测试连接。安装 PostgreSQL 客户端后执行:
psql "host=服务器IP port=5432 user=postgres dbname=postgres password=你的密码"能进入 psql 提示符,远程连接就打通了。
2.3 远程连接报错排查清单
我整理了远程连接最常见的几类报错,每一条都对应具体的排查动作,直接对照着查:
| 报错现象 | 可能原因 | 排查与处理 |
|---|---|---|
| psql: error: connection refused | 数据库没监听外部地址,或端口未监听 | 检查 ss -lntup | grep 5432;核对 listen_addresses,重启服务 |
| FATAL: no pg_hba.conf entry for host | pg_hba.conf 缺少匹配网段规则 | 在 pg_hba.conf 末尾添加对应网段,reload |
| FATAL: password authentication failed | 密码错误或认证方式不匹配 | 确认密码;确认 pg_hba.conf 中认证方式为 scram-sha-256 |
| Connection timed out | 防火墙、安全组或网络路由不通 | 检查 ufw 和云安全组 5432 端口;尝试 ping 服务器 IP |
| SSL error: connection reset | 客户端 libpq 版本过旧 | 将客户端 psql 和 libpq5 升级到 14 以上版本 |
补充一个容易误判的地方:报错里出现 FATAL: no pg_hba.conf entry for host,很多人以为是在 PostgreSQL 端没放行,但实际原因是请求方的 IP 不在任何匹配规则里。例如你从公司出口 IP 连接,这个 IP 不在你写的 192.168.1.0/24 网段内,就会被拒绝。排错时先去看 pg_hba.conf 实际匹配了哪条规则,再看监听和防火墙。
还要提醒一下,pg_hba.conf 里默认的 local all postgres peer 那一行不要动。它的作用是让本机系统用户 postgres 通过 peer 方式免密登录,用于本地管理。如果你把这行改成 scram-sha-256,又没记牢 postgres 密码,本机进入数据库都会变得很麻烦。
3. 常用插件:先装监控,再装功能
3.1 必装的性能监控插件:pg_stat_statements 与 auto_explain
调试 PostgreSQL 性能,如果手里没有数据,全靠猜。所以插件安装的第一优先级是监控类插件,不是炫酷的功能扩展。pg_stat_statements 是 PostgreSQL 自带的 contrib 模块,能记录每条 SQL 的执行次数、总耗时、平均耗时、缓存命中情况,是定位慢查询和高频查询的核心工具。
它的安装分两步:第一步在 postgresql.conf 的 shared_preload_libraries 里加上插件名,这需要重启数据库;第二步在数据库里执行 CREATE EXTENSION。先编辑 postgresql.conf:
shared_preload_libraries = 'pg_stat_statements'重启 PostgreSQL 后,在 psql 里执行:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;注意,shared_preload_libraries 这行里如果还想加 auto_explain,就用逗号分隔,写成 pg_stat_statements, auto_explain。auto_explain 的作用是当某条 SQL 执行时间超过阈值时,自动把它的执行计划写进日志,不用手动去 EXPLAIN。对线上环境排查慢查询非常有用。配置方法是:
shared_preload_libraries = 'pg_stat_statements, auto_explain' auto_explain.log_min_duration = '1s' auto_explain.log_analyze = on auto_explain.log_buffers = on等于给慢查询装了行车记录仪。SQL 执行超过 1 秒,日志里就有它的执行计划和缓冲区使用情况。我一般会把阈值设置成业务可容忍延迟的下限,开发环境可以设 300ms,生产环境先设 1s,稳定后再逐步收紧。
3.2 功能扩展插件:从 PostGIS 到 pgvector
监控插件装完,再按业务需求装功能类插件。Ubuntu 上通过官方 apt 源安装 PostgreSQL 扩展的公式很固定——postgresql-18-加上插件名。例如:
sudo apt-get install -y postgresql-18-postgis-3 postgresql-18-pgvectorPostGIS 是空间地理数据扩展,pgvector 是向量检索扩展,后者在 AI 和语义搜索场景里用得很多。装完后在数据库里创建扩展:
CREATE EXTENSION IF NOT EXISTS postgis; CREATE EXTENSION IF NOT EXISTS vector;还有几个常用的小工具扩展:
CREATE EXTENSION IF NOT EXISTS pgcrypto; -- 加解密函数 CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- UUID 生成 CREATE EXTENSION IF NOT EXISTS pg_trgm; -- 模糊查询的 trigram 索引支持 CREATE EXTENSION IF NOT EXISTS unaccent; -- 去掉拼音符号,比如将 é 变为 e CREATE EXTENSION IF NOT EXISTS hstore; -- key-value 存储类型中文全文检索方面,如果有分词需求,可以考虑 zhparser。这个扩展在官方 apt 仓库里不一定有对应 PG18 的现成包,可能需要自行编译,或者选择 PGroonga 这类第三方扩展。建议安装前先在官方扩展列表页确认当前版本支持的扩展清单。
3.3 插件管理注意事项
插件安装有几个常见的坑,我在实际部署中几乎每次都会遇到新人踩:
第一,shared_preload_libraries 里面声明的插件,必须重启数据库才能生效;CREATE EXTENSION 创建扩展本身不需要重启。很多人改了 preload 配置不重启,直接 CREATE EXTENSION,然后发现表不存在或视图为空;反过来,有些插件不修改 preload 也能创建扩展,但相关功能没加载,比如 pg_stat_statements 建完后查询视图没有数据。
第二,扩展的名称和 apt 包名不一定一致。apt 安装的是 postgresql-18-pgvector,但 psql 里创建的扩展名是 vector。apt 包名要查仓库,CREATE EXTENSION 名称要进 psql 里查询:
SELECT * FROM pg_available_extensions;第三,扩展不是越多越好。每引入一个扩展,都增加了系统表的复杂度和升级时的兼容性成本。一个四五年不清理的数据库,最终可能积累了几十个锚定到具体全版本的旧扩展,升级大版本时这些扩展反而变成阻碍。
第四,如果是在已有业务库上装插件,最好先确认当前用户有创建扩展的权限。多数情况下需要超级用户执行,或者由管理员创建后,再把使用权限授权给业务用户。
4. 性能调优实战:先看数据,再动参数
4.1 建立性能基线:TOP SQL 与慢查询日志
调优的第一步永远是建立基线。没有基线,你改完参数后根本说不清是变好了还是变坏了。我建议刚部署完 PostgreSQL 18,在业务流量进来之前就做两件事:
一是打开 pg_stat_statements,跑几天真实流量,或者用压测工具制造负载,然后查 TOP SQL:
SELECT calls, round(total_exec_time::numeric, 2) AS total_ms, round(mean_exec_time::numeric, 2) AS mean_ms, query FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 10;二是打开慢查询日志。在 postgresql.conf 里设 log_min_duration_statement = 1000,日志里就会记录超过 1 秒的 SQL。通过这条日志可以快速定位到底哪些查询拖垮了系统,是缺少索引,还是统计信息不准,或者是排序/哈希操作太重。
真实场景里,性能问题来自源代码的比例远低于来自数据分布和配置的不匹配。比如某个表数据量涨了十倍,统计信息没更新,执行计划就会选出糟糕的访问路径。所以调优前先看数据,再改参数,这个顺序千万别反。
4.2 内存与并发参数的计算逻辑
PostgreSQL 调优最核心的参数就几个:shared_buffers、effective_cache_size、work_mem、maintenance_work_mem、max_connections。很多人直接抄网上的配置,其实这些参数和机器配置强相关,抄不来的。
先说 shared_buffers。它是 PostgreSQL 自己的缓冲池,放表和索引的缓存。官方建议设为物理内存的 25%,低层代码实际会按块数做向上取整,所以不用纠结精确值。假设一台 8G 内存的服务器,设 2GB 比较合理,即 shared_buffers = 2GB。如果机器是 32G 内存,设 8GB 左右,但注意超过 32G 配置时,对 TPS 的提升就不明显了。
然后是 effective_cache_size。这个参数并不分配内存,只是告诉优化器操作系统页缓存大概有多大,用于评估走索引扫描还是顺序扫描的成本。推荐设为物理内存的 50% 到 75%。8G 内存设为 6GB 比较稳。如果你设置过小,优化器会低估顺序扫描的优势,倾向走索引;设置过大,又可能反过来。
work_mem 是每个排序操作和哈希操作能使用的内存。这个参数特别容易踩坑——它按操作分配,不是按连接分配。一条查询里可能同时有几个排序和哈希操作,每个操作都能吃满 work_mem。如果并发一大,你设的 1GB work_mem 会被放大成几十个 GB,直接触发 OOM。保守起见,我建议初始按这个公式估算:work_mem = (游离内存 / max_connections) / 2。在 8G 内存、100 连接的场景,我会先设 16MB,观察 pg_stat_statements 和系统日志,如果出现临时文件落盘再调大,而不是一步到位设几 GB。
maintenance_work_mem 用于 VACUUM、CREATE INDEX 这类维护操作。它不需要像 work_mem 那样克制,设 512MB 到 1GB 都安全,因为 VACUUM 同时运行的并发数不高。
还有一个容易忽略的提醒:不要单独调大某个参数。所有这些内存参数共同决定了内存的占用总量。即使每个参数单独看都很小,乘上并发和连接数也可能吃光内存。调完参数后,用 free -h 观察可用内存,用 dstat 或者 atop 观察 swap 使用情况,一旦开始用 swap,说明内存参数可能设置过头了。
4.3 WAL 与检查点参数调整
WAL 是 PostgreSQL 的预写日志,它有两个作用:崩溃恢复和流复制基础。对性能的影响主要体现在检查点频率和 WAL 写入行为上。
max_wal_size 决定两个检查点之间 WAL 可以撑多大。默认 1GB,如果业务写入量大,检查点会频繁触发,导致磁盘 IO 波动。可以把 max_wal_size 调大到 4GB 或更大。min_wal_size 保持默认即可,它是回收和保留之间的平衡值,通常不用动。
checkpoint_completion_target 控制检查点刷盘的速度按计划分摊。默认 0.5,设到 0.9 可以把刷脏缓冲区的压力分散到整个检查点周期内,避免周期性 IO 尖峰。这个参数对机械硬盘效果明显,对 SSD 也有一定作用。
如果你用的是 SSD,random_page_cost 建议从默认的 4 调到 1.1。这个参数表示随机读取一次页面的成本,HDD 随机寻道代价高,所以默认是 4;SSD 随机和顺序读取差不多,设置为 1 到 1.1 更贴近真实,也能让优化器更愿意选择索引扫描。我刚调完这个参数时,遇到过几条慢 SQL 从顺序扫描变成索引扫描,效果出乎意料地好。
fsync 这个参数不建议关闭。它保证数据库崩溃后数据能恢复。网上有些人为了极限性能把 fsync = off,一旦系统掉电,整个数据库可能直接损坏且无法恢复,这种代价不是几百毫秒性能能弥补的。调优永远要在性能和可靠性之间找平衡。
4.4 查询与索引优化思路
参数调整只能解决系统级瓶颈。大量慢查询的问题根源其实在 SQL 写法、表结构设计和索引缺失上。通过 pg_stat_statements 找到高频查询后,对单条慢查询要做的第一件事是 EXPLAIN:
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM orders WHERE user_id = 123;重点看三个东西:有没有出现 Seq Scan 全表扫描,有没有 Sort 排序操作,有没有 Nested Loop 循环嵌套里套了一次低效的内层扫描。这三个点对应的常规优化手段是建索引、调整 work_mem、改写 JOIN。
索引设计上,一个很实用的组合是:高频且带等值条件的查询,用 btree 单列索引;模糊查询 ILIKE '%xxx%',用 pg_trgm 的 GIN 索引;如果查询同时带地理位置和其他条件,用 PostGIS 的组合索引。但这些索引不是越多越好,每个索引都会拖慢 INSERT、UPDATE 和 DELETE 的写入速度。我曾见过一张表有 7 个无用的单列索引,写入性能比删除索引后慢了近 30%。
另一个经常被忽略的是 autovacuum。PostgreSQL 的并发控制机制导致被删除或者更新的行不会立刻物理撤销,而是在表里留下一堆死元组。必须靠 VACUUM 清理。默认的 autovacuum 参数一般够用,但如果业务频繁更新,建议检查 autovacuum_vacuum_scale_factor,默认是 0.2,即表里 20% 的元组成为死元组才触发,对大表来说太晚了。可以把这个值调到 0.05 或 0.1,配合定时调度在低峰期执行 VACUUM。
4.5 用 pgbench 验证调优效果
调优不能靠感觉,得用数据说话。PostgreSQL 自带的 pgbench 就是最可靠的压测工具。先初始化测试数据:
sudo -u postgres pgbench -i -s 20 postgres-s 20 表示生成 20 倍于默认规模的测试数据,大约 200MB,足够模拟真实负载。然后执行压力测试:
sudo -u postgres pgbench -c 10 -j 2 -T 60 -P 5 postgres-c 10 是并发连接数,-j 2 是线程数,-T 60 是测试时长 60 秒,-P 5 是每 5 秒打印一次进度。执行完会看到 TPS 和平均延迟。调参前记录一次,调参后记录一次,对比两个数值,就能客观评估调优是否有用。
我实际测试中发现,单纯调内存参数对 OLTP 型负载的 TPS 提升通常只有个位数到百分之二三十;而把 shared_buffers 和 work_mem 调整合适后,再加上针对性索引,TPS 翻倍是很常见的。这也再次说明,先建基线、再定位问题 SQL、再改参数,这个流程的价值远大于盲目抄配置。
5. 常见问题与排查实例速查
我整理了 PostgreSQL 18 在 Ubuntu 24.04 上从安装到调优最常遇到的几类问题,做成一个速查表:
| 现象 | 可能原因 | 排查与解决 |
|---|---|---|
| apt 源添加后 update 报错 | 仓库代号或签名密钥问题 | 确认 Ubuntu 24.04 对应 noble;重装 postgresql-common 后重新运行官方脚本 |
| 安装后在 /etc/postgresql 下没有看到 18 目录 | PostgreSQL 服务可能没初始化 | 执行 sudo pg_createcluster 18 main 初始化,再启动 |
| 本机可以连接,外部连接拒绝 | 监听地址、防火墙或安全组 | 检查 listen_addresses,检查 ufw 状态,检查云安全组 |
| pg_stat_statements 视图为空 | shared_preload_libraries 未配置或未重启 | 确认配置文件里已加上,并重启 postgresql@18-main |
| CREATE EXTENSION 报版本不匹配 | apt 包版本和数据库版本不一致 | 确认安装的是 postgresql-18-* 的包,不要装旧版扩展包 |
| work_mem 调大后系统开始使用 swap | 连接或并发数过高导致内存超分配 | 降低 work_mem,或引入连接池限制并发 |
| VACUUM 频繁触发导致 IO 波动 | autovacuum 参数过激进 | 将 autovacuum_vacuum_scale_factor 调回 0.1 左右 |
| psql 客户端太旧连接 PG18 报 SSL 错误 | libpq 版本过旧 | 安装新版本 postgresql-client 或 libpq5 |
再分享一个真实排错场景。有一次同事反馈某个应用服务器连不上数据库,报错是 FATAL: no pg_hba.conf entry for host。我们先是加了应用服务器内网 IP 的规则,reload 后还是报错。最后用 pg_hba.conf 里的注释格式检查发现,我们新增规则的位置在文件末尾并不生效,因为该集群定义的连续规则中有一条更靠前的 host all all 0.0.0.0/0 scram-sha-256 规则已经匹配了所有来源,却因为没有准确包含目标 IP 而失败。后来把放在前面的配置规则整理到 expected 位置,问题才解决。这个经验是:pg_hba.conf 的匹配规则按从上到下的顺序执行,第一条匹配的规则生效。排错时先检查已生效的匹配顺序,再查规则本身。
还有一点,公司内部的 PostgreSQL 客户端版本五花八门,尤其是老的 CentOS、Windows 机器上装的老版 psql,连接 PostgreSQL 18 时很可能报 SSL 协议错误,因为 PG18 默认禁用了旧版 TLS。遇到这种问题,优先升级客户端到 PostgreSQL 14 以上版本,而不是关掉数据库的 SSL 配置。在安全性和兼容性面前,升级客户端是更正确的选择。
最后说一个我个人的习惯:每次调整 PostgreSQL 配置前,先备份一份配置文件,记录下改动的时间、参数、原因。上线前跑一次 pgbench,调完后再跑一次,把两次结果贴在变更记录里。这样做看起来慢,但几个月后回头看,你能清晰地说出每次改动带来的实际收益,而不是靠感觉。一个简单的命令就够:
sudo cp /etc/postgresql/18/main/postgresql.conf /etc/postgresql/18/main/postgresql.conf.bak-$(date +%Y%m%d-%H%M)这套操作下来,Ubuntu 24.04 上的 PostgreSQL 18 就能稳定跑起来:远程连接可控、插件按需加载、性能参数有据可调。如果你在部署中遇到别的报错,把报错原文和 pg_hba.conf 的当前内容对照一遍,大部分问题都能快速定位。