发布时间:2026-09-16 12:31 更新时间:2026-09-16 12:31 阅读量:0
不少站长从 MySQL 转到 PostgreSQL,第一件事就是按老习惯把 max_connections 调到 500 甚至 1000,觉得连接数越大越能扛并发。上线没几天,服务器内存被吃满,OOM 把数据库进程干掉,业务直接中断。问题不在连接数本身,而在于 PostgreSQL 的进程模型:每个客户端连接对应一个独立后端进程,会各自占用一份私有内存,连接数翻倍,内存开销也跟着翻倍。这篇就讲清楚连接数和内存之间的账怎么算,以及 shared_buffers 该给多少。
PostgreSQL 采用「一个连接一个进程」的架构,也就是说,连接不是轻量的线程,而是实打实的操作系统进程。每个后端进程除了共享内存之外,还会分配自己的私有内存,主要来自 work_mem 以及排序、哈希、维护操作时的临时空间。单个连接空闲时看着不大,一旦跑起复杂查询,work_mem 会成倍叠加。
粗略估算公式可以记成:峰值内存 ≈ shared_buffers + max_connections × (work_mem × 并发排序数 + 每连接固定开销)。其中每连接固定开销没有统一标准,通常按几 MB 到十几 MB 估,具体以实际环境和官方文档为准。如果 max_connections 设成 500、work_mem 设成 16MB,光排序内存理论上限就能到 8GB,再加上 shared_buffers,小内存机器根本扛不住。
所以更稳妥的思路是:把 max_connections 控制在应用连接池实际需要的范围内,而不是给每个可能发起的连接都留位置。PHP-FPM、Java 连接池、Go 的 sql.DB 都应该设置上限,超出部分排队或快速失败,比让数据库硬扛更健康。PostgreSQL 预留的 superuser_reserved_connections 会为管理员保留几个连接,紧急时能用超级用户登进去处理问题。
-- 查看当前连接使用情况与各库连接数
SELECT count(*) AS total, state FROM pg_stat_activity GROUP BY state;
-- 查看关键参数当前值
SHOW max_connections;
SHOW shared_buffers;
SHOW work_mem;
如果确实需要更多并发连接,可以评估连接池中间件(如 PgBouncer),它把大量客户端连接复用成少量数据库连接,能显著降低后端进程数量。是否引入要看业务形态,别为了省内存引入新的单点。
shared_buffers 是 PostgreSQL 自己管理的数据缓存区,用来缓存表和索引的数据页,所有连接共享这一块。它不像 MySQL 的 InnoDB Buffer Pool 那样通常建议给到物理内存的一大半,PostgreSQL 还依赖操作系统的页缓存,两者是协作关系,所以 shared_buffers 给得过大反而可能挤占系统缓存,收益递减。
实践中的常见起点是物理内存的 25% 左右,专用数据库服务器可以适当上调,但一般不建议超过内存的一半,具体以实际压测和官方文档为准。比如 8GB 内存的机器,shared_buffers 从 2GB 起步比较稳妥;16GB 的机器可以给 4GB 左右。改完以后一定要留出足够内存给操作系统和每个连接进程。
另外,PostgreSQL 9.3 之后 shared_buffers 的修改需要重启生效,不能只 reload。配置项单位可以用 MB 或 GB,写 2GB 比写 2048MB 更直观。除了 shared_buffers,work_mem 是单连接级别的,调大它会让每个排序操作占用更多内存,高并发时风险更大;maintenance_work_mem 影响 VACUUM、CREATE INDEX 等维护操作,可以单独给大一些。
# 在 postgresql.conf 中调整(路径以实际安装为准)
8GB 内存机器的保守起点
shared_buffers = 2GB
max_connections = 100
work_mem = 4MB
maintenance_work_mem = 256MB
注意不要直接编辑 postgresql.auto.conf,那是 ALTER SYSTEM 命令自动维护的文件。手动改配置请改 postgresql.conf,或者用 ALTER SYSTEM SET 写入,后者会自动落到 auto.conf 并覆盖前者同名项,排查时容易看花眼。
PostgreSQL 的参数分两类:一类改完 reload 就能生效,比如 work_mem(对新连接和后续操作生效);另一类必须重启,比如 shared_buffers、max_connections。判断标准可以查 pg_settings 的 context 字段,或者直接看官方文档的参数说明。
# 平滑重载配置(不中断现有连接)
sudo systemctl reload postgresql
或使用 pg_ctl
sudo -u postgres pg_ctl reload -D /var/lib/postgresql/data
需要重启的参数(如 shared_buffers、max_connections)
sudo systemctl restart postgresql
验证参数是否已加载
sudo -u postgres psql -c "SHOW shared_buffers;"
sudo -u postgres psql -c "SHOW max_connections;"
如果是用 Docker 跑的 PostgreSQL,reload 和 restart 要对应到容器,注意配置目录挂载和命令的区别,具体以镜像文档为准。修改前建议先备份 postgresql.conf,改完用 pg_ctl reload 或 systemctl reload 触发,再查一遍 SHOW 确认值已变。重启前务必确认没有长时间运行的大事务,避免影响业务。
最后提醒两点:一是调参不要一次改多个,改一个观察一段时间,方便定位问题;二是内存估算要留安全余量,操作系统、监控代理、其他服务都占内存,别按物理内存满打满算。把 max_connections 控制在连接池需要范围内,shared_buffers 按内存 25% 起步,再配合 pg_stat_activity 观察真实连接峰值,通常就能让这台数据库稳稳跑起来。
| 📑 | 📅 |
|---|---|
| Linux文件句柄耗尽排查:Too many open files 从ulimit到systemd | 2026-09-16 |
| Nginx 后端真实 IP 获取:X-Forwarded-For 与 real_ip 配置 | 2026-09-16 |
| rsync 增量同步与断点续传实战:exclude、--delete 与限速 | 2026-09-16 |
| MySQL 主从延迟排查:Seconds_Behind_Master 忽高忽低怎么定位 | 2026-09-16 |
| 容器内存超限被 OOM Kill 排查:指标、cgroup 与堆参数对应 | 2026-09-16 |
| 服务器时间不同步导致证书与定时任务异常:NTP/chrony 校时配置与排查 | 2026-09-16 |
| Linux内存被缓存吃满:buff/cache该不该手动释放 | 2026-09-17 |
| SSH 连接频繁断开与卡顿排查:心跳、MTU 与 DNS 反解 | 2026-09-17 |
| MySQL表空间与ibdata1膨胀处理:独立表空间、碎片整理与磁盘回收 | 2026-09-17 |
| 系统盘满了却找不到大文件:被删除但仍被进程占用的句柄排查与恢复空间 | 2026-09-17 |