很多人在这台服务器上折腾数据库时,最容易踩的坑就是:明明是 Ubuntu 24.04,执行apt install postgresql后却发现自己装的是 16,而不是标题里想用的 PostgreSQL 18。如果你准备从零搭一套 PostgreSQL 18,并且想一次性搞定远程连接、常用插件和性能调优,这篇实操记录会很对路。全文基于跑在 Ubuntu 24.04 上的完整过程,每一步都给出可直接复制的命令,同时把我踩过的坑和最后保留的配置方案一起放出来。
1. 先别急着apt install:24.04 自带版本与 PGDG 源怎么选
1.1 Ubuntu 24.04 官方仓库里的 PostgreSQL,为什么不是 18
Ubuntu 24.04(代号 noble)发布时,官方源里默认的 PostgreSQL 是 16.x。对大多数场景来说,16 足够稳定,但它和 18 之间隔了不小的代差:18 在 vacuum、逻辑复制、并行任务调度、IO 同步策略等方面都有一批新的改进。如果你本地测试或新项目想要直接跟上 18,光靠系统自带源是没希望的,连apt-cache policy postgresql查出来的候选版本都只会是 16。
这不是 Ubuntu 不给新版本,而是发行版的更新策略本就偏向保守。系统仓库要保证整个系统组件之间的兼容性,不会把大版本数据库随意升级。想要在 Ubuntu 24.04 上装 PostgreSQL 18,主流做法是把 PostgreSQL 官方维护的 PGDG 源加进来,从那里安装postgresql-18包。
1.2 PGDG 源和系统自带源的本质区别
PGDG(PostgreSQL Global Development Group)源可以理解成 PostgreSQL 官方自己的软件仓库。Ubuntu 源里的 postgresql 包由发行版团队维护,而 PGDG 的包由 PostgreSQL 社区持续打包、同步新版本,因此你能在 PGDG 里同时看到 16、17、18 等所有活跃版本的安装包。
选择 PGDG 的另一个实际理由:插件包。像postgresql-18-pgvector、postgresql-18-postgis-3、postgresql-18-pg_stat_statements这类扩展包,很多在 Ubuntu 官方源里没有,或者在版本匹配上很折腾。PGDG 对每个 PostgreSQL 主版本都打了一套插件包,命名规则是postgresql-18-插件名,安装时不会出现“服务器是 18,插件却只能装 16 版”这种错位。
需要注意的是,一旦添加 PGDG,apt install postgresql的行为会改变:系统会优先从 PGDG 解析出最新版本包,而不是 Ubuntu 自带的 16。所以我的习惯是:明确安装postgresql-18,不要偷懒装一个不带版本号的postgresql,否则哪天apt upgrade可能把默认 PostgreSQL 主版本带到更高版本,触发集群升级流程。
2. 从加源到服务跑起来:安装 PostgreSQL 18 的完整链路与集群管理
2.1 添加 PGDG 源的四个步骤
先确保基本工具在:
sudo apt update sudo apt install -y wget ca-certificates gnupg lsb-release导入 PostgreSQL 官方签名密钥。这里的install -d是创建带正确权限的目录:
sudo install -d /usr/share/postgresql-common/pgdg sudo install -d /etc/apt/keyrings wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | \ gpg --dearmor | sudo tee /etc/apt/keyrings/pgdg.gpg > /dev/null写入 apt 源。Ubuntu 24.04 已经支持 deb822 格式,我个人推荐把配置写到单独的.sources文件里,方便以后停用:
sudo tee /etc/apt/sources.list.d/pgdg.sources > /dev/null <<EOF Types: deb URIs: https://apt.postgresql.org/pub/repos/apt/ Suites: noble-pgdg Components: main Architectures: amd64 Signed-By: /etc/apt/keyrings/pgdg.gpg EOF更新索引后直接安装:
sudo apt update sudo apt install -y postgresql-18装完以后,系统会自动创建一个叫main的集群,数据目录在/var/lib/postgresql/18/main,配置文件在/etc/postgresql/18/main/。Debian 系 PostgreSQL 的惯例是一个主版本对应一个实例目录,里面再分多个集群,这是和 CentOS 上单目录安装最大的区别。
2.2 用 pg_lsclusters 管理多集群,避免端口和启动顺序混乱
安装完成第一步,我不会急着去psql,而是先看集群状态:
pg_lsclusters输出会告诉你每个集群的版本、名称、端口、数据目录和当前状态。刚装完 18,正常情况下你会看到类似:
18 main 5432 online /var/lib/postgresql/18/main但如果这台机器之前装过系统自带的 16,情况会变成两个集群:16 占着 5432,18 自动分到 5433。遇到这种情况,你不需要两台数据库在同一端口上互相竞争。最干净的做法是,如果 16 完全是多余的系统默认包,就直接卸载:
sudo apt purge -y postgresql-16 postgresql-client-16如果 16 上有老库,那你需要给 16 换一个端口,比如 5433,然后把 18 留在 5432。改端口的方法是在对应集群的配置文件postgresql.conf里改port = 5433,然后重启:
sudo pg_ctlcluster 16 main restart2.3 验证安装并处理基础认证
检查版本和服务状态:
psql --version sudo systemctl status postgresql@18-main接着登录 PostgreSQL,设置postgres用户的密码。这里直接设置强密码,因为后面远程连接测试会用到它:
sudo -u postgres psql在psql里执行:
ALTER USER postgres PASSWORD '一个强密码';如果你用的是 Ubuntu 24.04,默认密码加密方式是scram-sha-256,不需要额外改动。这一步顺便解释一下 Debian 系 PostgreSQL 的设计:操作系统层面有一个postgres系统用户,数据库里也有一个同名超级用户。本地第一次登录必须通过sudo -u postgres psql走 peer 认证,而不是随便输密码。很多人第一次卡在“我明明设置了 postgres 密码为什么登录不了”,多半就是没搞懂这个 peer 认证的前提。
3. 远程连接的三道关卡:监听地址、认证规则与防火墙
3.1 第一关:让 PostgreSQL 真正监听外部网卡
PostgreSQL 默认只监听localhost,所以远程客户端即使防火墙全开也连不上。打开主配置:
sudo nano /etc/postgresql/18/main/postgresql.conf找到这一行:
#listen_addresses = 'localhost'改成:
listen_addresses = '*'如果你只想让某个内网网段访问,可以写具体的 IP,比如'127.0.0.1, 192.168.10.5'。我强调一下:listen_addresses属于需要 reload 就能生效的参数,不需要重启,真正卡住远程连接的往往是下一关。
注意:Debian 系 PostgreSQL 的配置优先级大致是
postgresql.conf<postgresql.auto.conf<conf.d目录下的文件。ALTER SYSTEM写进postgresql.auto.conf的配置会覆盖postgresql.conf。你手动改完postgresql.conf如果发现没生效,先怀疑是不是有auto.conf或conf.d里的同名配置把它盖住了。
3.2 第二关:pg_hba.conf 的认证规则必须匹配连接来源
这是远程连接失败率最高的一处。打开同目录下的pg_hba.conf:
sudo nano /etc/postgresql/18/main/pg_hba.conf文件底部默认只有本地规则,比如:
local all postgres peer local all all peer host all all 127.0.0.1/32 scram-sha-256 host all all ::1/128 scram-sha-256在文件末尾追加外部访问规则。如果你放心大范围访问,可以写:
host all all 0.0.0.0/0 scram-sha-256 host all all ::/0 scram-sha-256生产环境我更推荐你写成明确网段,例如只允许内网:
host all all 192.168.1.0/24 scram-sha-256方法字段必须和你数据库里用户的密码存储方式一致。Ubuntu 24.04 上 PostgreSQL 默认password_encryption = scram-sha-256,所以这里用scram-sha-256完全没问题。如果你在旧系统上迁移过来,用户密码还是 md5 格式,而 pg_hba 里写的是 scram-sha-256,那么认证会失败,日志里报的就是 password authentication failed。排查时可以先用scram-sha-256,如果报错再看日志确认。
3.3 第三关:ufw 防火墙和云服务器安全组
改完配置后先 reload 让规则生效:
sudo systemctl reload postgresql@18-main然后放行端口:
sudo ufw allow 5432/tcp注意:如果你用的是云服务器,光开 ufw 还不够。控制台里的安全组/防火墙规则也要放行 TCP 5432。这两层是独立工作的,任何一个没放行,远程都会表现为 Connection refused 或者超时。我的排查顺序是:先 PSQL 本机测试,确认服务正常;再看 ufw 规则;最后看云控制台安全组。
本机自测命令:
psql -h 127.0.0.1 -U postgres -d postgres远程机器测试:
psql -h 服务器IP -U postgres -d postgres -W如果提示连接被拒,先检查服务是否监听在正确地址上:
ss -lntp | grep 5432正常的输出里会看到类似0.0.0.0:5432或*:5432。如果只显示127.0.0.1:5432,说明listen_addresses没生效。
3.4 远程连接报错速查表
我在实际帮别人排查时,把最常见的几种现象整理成了表格,你照着核对基本能快速定位:
| 现象 | 可能原因 | 下一步 |
|---|---|---|
| Connection refused | postgresql 服务没启动,或端口被防火墙拦截 | 查pg_lsclusters、ss -lntp、ufw 状态 |
| timeout 超时 | 云服务器安全组未放行 | 检查控制台安全组入方向规则 |
| no pg_hba.conf entry | 客户端来源 IP 没有匹配到的 host 规则 | 补上对应网段的 host 记录并 reload |
| password authentication failed | 密码错,或 pg_hba 的 method 与存储的密码加密格式不一致 | 重置密码,或统一使用 scram-sha-256 |
| SSL 相关警告 | PostgreSQL 默认没启用 SSL,客户端只是收到警告 | 不影响功能;如需强制加密,配置 ssl 并改用 hostssl 规则 |
远程连接通畅之后,安全上要注意:不要长期用超级用户postgres给业务应用连库。正确姿势是创建一个专用业务账号,只授权它需要的数据库和权限,并且尽量限制来源 IP 网段。如果条件允许,更进一步的做法是让应用通过 SSH 隧道访问数据库,而不把 5432 直接暴露给公网,能省去很多被扫描攻击的麻烦。
4. 常用插件:一条龙装齐扩展,别忽略预加载参数
4.1 插件包的命名规则和安装方式
在 Ubuntu 24.04 + PGDG 环境下,插件安装的包名可以直接猜:postgresql-18-插件名。常用的有:
sudo apt install -y postgresql-18-pg-stat-statements postgresql-18-pgvector postgresql-18-postgis-3插件包安装完成不等于扩展已经在数据库里生效。还需要在具体数据库里执行CREATE EXTENSION,并且一部分插件需要预加载配置才能完整工作。这里列几个我认为真正用得上的插件,以及它们的配置要点。
4.2 pg_stat_statements:必装的性能监控插件
这个插件是我强烈建议第一个装的。它记录每条 SQL 的执行次数、总耗时、平均耗时、缓冲命中情况,是后续性能调优最直接的依据。它需要加载到共享库才能在实例级别采集数据:
修改追加到postgresql.conf:
shared_preload_libraries = 'pg_stat_statements' pg_stat_statements.max = 10000 pg_stat_statements.track = all注意:shared_preload_libraries的修改必须重启数据库,reload 不生效:
sudo systemctl restart postgresql@18-main然后在数据库里执行:
CREATE EXTENSION pg_stat_statements;查询 TOP 慢 SQL:
SELECT calls, total_exec_time, mean_exec_time, rows, query FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 10;如果查询结果全为空,先确认扩展是否建在你要观察的那个数据库里。pg_stat_statements是实例级采集,但扩展必须在你连接的数据库中创建后,你才能查询到对应视图。
4.3 pgvector:向量检索入门的核心扩展
如果你以后想在本地上跑 RAG 类应用,pgvector 是绕不开的扩展。安装:
sudo apt install -y postgresql-18-pgvector创建扩展的语法非常直接:
CREATE EXTENSION vector;验证版本:
SELECT extversion FROM pg_extension WHERE extname = 'vector';pgvector 的使用方式是在建表时把字段类型写成vector(维度),比如:
CREATE TABLE items ( id bigserial PRIMARY KEY, embedding vector(1536) );创建 hnsw 索引时,注意索引类型名前要加vector,并且在 PostgreSQL 16 以上版本使用:
CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops);我的经验是:别为了图方便把所有向量字段都建成同一维度,后续模型切换时维度不匹配会让你重新迁移数据。
4.4 postgis:地理空间扩展的安装重点
安装包:
sudo apt install -y postgresql-18-postgis-3然后在目标数据库中执行:
CREATE EXTENSION postgis;PostGIS 的包体积比较大,依赖也比较多。如果你只是做简单坐标计算,可以考虑先只装 postgis,不要一次性装全套依赖。创建扩展后,验证:
SELECT PostGIS_Version();4.5 轻量插件:uuid-ossp、pgcrypto、citext、hstore
这几个扩展各有适用场景,安装方式也是在对应数据库里执行:
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE EXTENSION IF NOT EXISTS pgcrypto; CREATE EXTENSION IF NOT EXISTS citext; CREATE EXTENSION IF NOT EXISTS hstore;uuid-ossp:提供uuid_generate_v4(),适合主键生成。pgcrypto:提供加密函数和gen_random_uuid(),PostgreSQL 13 以后gen_random_uuid()已经内置,但pgcrypto里还有别的加密函数。citext:大小写不敏感的文本类型,省去到处写lower()。hstore:key-value 存储,适合扩展字段灵活变化的场景。
创建扩展时的权限要注意:CREATE EXTENSION需要超级用户权限。我建议所有扩展都用postgres用户创建好,再给业务账号分配使用权限,不要给业务账号超级用户权限。
4.6 扩展创建到哪个数据库?
这是新手最容易忽略的一点。PostgreSQL 的扩展是数据库级的,不是实例级的。你在postgres库里创建了 pg_stat_statements,换到业务库依然需要再执行一次CREATE EXTENSION pg_stat_statements;。尤其是postgis、pgvector这类重量级扩展,业务库和默认库都得各自创建。如果CREATE EXTENSION时报找不到扩展,确认包安装的版本和服务器主版本是否一致,例如 PostgreSQL 18 的服务器不能直接加载postgresql-16-postgis装出来的.so文件。
5. 性能调优:先算清内存账,再动配置
5.1 调优不是抄参数,而是先算你能用多少内存
很多网上的 PostgreSQL 调优配置看起来很有道理,直接抄到自己的服务器上却可能把实例拖垮。原因很简单:work_mem这类参数是“每个连接每次排序/哈希操作”都可能分配的内存,并发一高,总量会非常恐怖。
先把服务器的资源摸清楚。假设手上是一台 8GB 内存、4 核 CPU 的通用服务器,业务类型以 OLTP 为主,目标是稳定跑日常线上服务。按照下面的思路算账:
shared_buffers:PostgreSQL 自有的共享缓存,通常建议为物理内存的 25%。8GB 内存就是 2GB。不要盲目往上加,超过物理内存的 1/3 后收益会明显下降,因为操作系统页缓存同样重要。effective_cache_size:这个参数告诉优化器操作系统页缓存有多大,它不真正分配内存,只影响执行计划。建议设置为物理内存的 50%~75%,8GB 内存可以给 6GB。work_mem:默认 4MB 对排序场景往往偏小,但也不能拍脑袋给 1GB。并发 50 个连接同时做排序,如果 work_mem = 256MB,理论最高就要吃 12GB 内存,直接打爆 8GB 机器。OLTP 场景一般给 16MB~32MB 起步。maintenance_work_mem:VACUUM、CREATE INDEX、加约束时使用的内存,可以给 512MB,对维护任务提速明显,因为它不会同时并发几十份。
5.2 一套适合 4C8G 起步环境的参数配置
下面是基于上述思路整理的一套可复制配置,直接追加到postgresql.conf或使用ALTER SYSTEM:
shared_buffers = 2GB effective_cache_size = 6GB work_mem = 16MB maintenance_work_mem = 512MB max_connections = 200 random_page_cost = 1.5 checkpoint_completion_target = 0.9 max_wal_size = 2GB min_wal_size = 512MB synchronous_commit = off jit = off这里有几个参数需要说明为什么这么设:
random_page_cost默认是 4.0,这个值最初是机械硬盘时代的经验值。如果你的数据盘是 SSD 或 NVMe,随机读代价远没有那么高,建议降到 1.5 左右。优化器会因此更愿意走索引扫描而不是全表扫描,在很多查询里能带来肉眼可见的提速。
synchronous_commit = off是把事务提交的 fsync 同步要求放宽:事务不等 WAL 刷盘完成就返回成功,写入吞吐会明显提升。代价是极端断电场景下可能丢失最近一小段时间内已提交的事务。如果你是个人测试、作业调度或可以接受少量数据回退的场景,可以开;如果是金融交易类业务,建议保持默认 on。
jit = off是另一个容易踩坑的地方。PostgreSQL 的 JIT 对复杂大查询有用,但对 OLTP 场景里大量小而快的查询,编译开销反而可能拖慢执行。如果你的业务以短查询为主、又不想每次排查都看到 JIT 的编译时间,直接关掉。
使用ALTER SYSTEM的好处是不用手动编辑文件,它会写进postgresql.auto.conf:
ALTER SYSTEM SET shared_buffers = '2GB'; ALTER SYSTEM SET effective_cache_size = '6GB'; ALTER SYSTEM SET work_mem = '16MB'; ALTER SYSTEM SET maintenance_work_mem = '512MB'; ALTER SYSTEM SET jit = off;改完需要重启的参数有shared_buffers、jit、max_connections。work_mem、effective_cache_size、random_page_cost是 reload 即可:
sudo systemctl restart postgresql@18-main5.3 别忽视连接数和你实际并发的关系
max_connections默认是 100,很多业务其实够用。如果你用连接池处理应用连接,数据库侧的实际连接数会被压得很低,不需要把 max_connections 调到 500。要警惕的是连接数一旦提高,work_mem的放大效应会非常明显。极端情况估算一下:200 个连接同时执行排序,每个排序用 16MB,总占用大约 3.2GB,加上 shared_buffers 2GB、系统和其他进程占用,8GB 机器会靠到红线。所以连接数和工作内存要放在一起调,不能单独盯着一个参数改。
5.4 从 SQL 层面挖性能问题比调参更重要
参数调优只能帮你解决“地基”问题,真正让查询慢的往往是烂 SQL 和缺失索引。在调参之后,我建议立刻打开慢查询日志:
在postgresql.conf追加:
log_min_duration_statement = 1000超过 1 秒的 SQL 都会出现在日志文件/var/log/postgresql/postgresql-18-main.log里。然后针对每条慢查询做:
EXPLAIN (ANALYZE, BUFFERS) SELECT ...;观察执行计划里有没有 Seq Scan 大表、有没有排序发生在内存之外、有没有嵌套循环特别离谱。大部分“数据库变慢”问题,最后看下来都是某一条 SQL 缺了索引或者写法有问题。
6. 配置生效后的验证与日常观察习惯
6.1 用 pg_stat_statements 复查调优效果
调优不能靠感觉,要有数据。重启或 reload 之后,查询几条关键数据:
SELECT round(total_exec_time) AS total_ms, calls, round(mean_exec_time) AS avg_ms, round(max_exec_time) AS max_ms, query FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 10;对比调优前后的 total_exec_time 和 mean_exec_time 是最直观的验证方式。如果你重启了实例,记得先跑一段时间业务,让 pg_stat_statements 积累数据,不然看到的是空表。
6.2 日常运维中几个值得养成的习惯
服务管理统一用 systemd:
# 查看状态 systemctl status postgresql@18-main # 重启 systemctl restart postgresql@18-main # 仅重载配置 systemctl reload postgresql@18-main注意 Debian 系 PostgreSQL 的多集群机制:systemctl管理的是具体某个集群服务,而不是笼统的 postgresql。如果你是手动管理集群,pg_ctlcluster 18 main restart也是对的,但生产环境建议统一用 systemd,便于开机自启和日志托管。
定期备份不要等到出问题才做。最简单的逻辑备份命令:
pg_dump -U postgres -d 数据库名 -F c -f 备份文件.dump恢复:
pg_restore -U postgres -d 数据库名 备份文件.dump这条命令虽然简单,但它应该是你所有调优、插件更新、大版本实验之前的第一件事。我吃过不少亏:改配置调优十分钟,结果一条 VACUUM 把磁盘占满了都没有备胎可回滚。
6.3 磁盘空间和监控的观察点
PostgreSQL 的 WAL 日志会占用磁盘,max_wal_size设得越大,WAL 堆积的天花板越高。检查磁盘空间:
df -h /var/lib/postgresql数据目录所在分区使用率一旦超过 85%,就该提前清理或扩容。清理不是让你手动删 WAL 文件,而是确认archive_mode、checkpoint和备份策略是否正常。手动删除 WAL 文件会让 PostgreSQL 直接拒绝启动,这是新手最容易踩的雷。
监控层面,如果你不想上专业监控系统,至少每周执行一次:
SELECT datname, pg_size_pretty(pg_database_size(datname)) FROM pg_database;看看哪个库增长异常,结合 pg_stat_statements 判断是不是有 SQL 制造了过多临时数据。
到这里,Ubuntu 24.04 上 PostgreSQL 18 的安装、远程连接、插件配置和性能调优已经完整跑通。最后分享一个我自己的习惯:每台服务器第一次装完 PostgreSQL,我都会立刻把 pg_stat_statements 配好,再把慢查询日志打开,之后所有调优动作都以这两份数据为依据,而不是靠感觉拍板。这套流程看起来不起眼,但它在无数个“数据库突然变慢”的深夜帮我把排查时间从几小时压缩到了几分钟。