max_connections 设置过高会直接压垮服务器内存,因其与work_mem及固定开销相乘导致内存超限,引发OOM、进程被杀或严重swap。

max_connections 设置过高会直接压垮服务器内存
PostgreSQL 每个连接都会独占一份 work_mem(以及少量固定开销),所以总内存消耗 ≈ max_connections × (work_mem + 约 10–20MB 固定开销)。比如设成 max_connections = 500、work_mem = 64MB,仅这部分就可能吃掉 30GB+ 内存,远超物理 RAM,触发 OOM killer 杀进程或严重 swap。
常见错误现象:out of memory 错误、PostgreSQL 进程被系统 kill、查询响应突然变慢甚至卡死。
- 不要按“最大并发用户数”设
max_connections,而应按“真实长期存活的后端连接数”估算(例如连接池如 PgBouncer 的 pool_size) - 生产环境建议初始值 ≤ 200;超过 300 必须同步压测内存与 swap 行为
-
max_connections修改需重启,不能热更新,别在线乱调
work_mem 动态放大效应比想象中更危险
work_mem 是每个 *操作节点*(如排序、哈希表、位图合并)独立分配的内存上限,不是每连接只用一份。一个复杂查询含 5 个排序 + 2 个哈希连接?可能瞬间申请 7 × work_mem。它还会在并行查询中被 worker 进程重复使用——1 个查询开 4 个 parallel worker,就可能占 4 × work_mem × 节点数。
典型踩坑场景:报表类查询在低峰期跑得通,高峰时因并发多、单查又重,集体触发内存争抢和频繁 swap。
- 全局设
work_mem到 128MB 以上前,务必用EXPLAIN (ANALYZE, BUFFERS)观察实际内存使用峰值 - 对 OLAP 查询,优先用
SET LOCAL work_mem = '512MB'在事务内临时调高,避免污染全局 - 注意
work_mem单位是 KB/MB/GB,写错单位(如写成work_mem = 64)会导致实际只有 64KB,反而引发大量磁盘排序
shared_buffers 和 effective_cache_size 不是“越大越好”
这两个参数常被误当作“能填多少填多少”,但它们和 max_connections、work_mem 共享同一块物理内存。Linux 内核对 shared memory(shared_buffers)有硬限制(/proc/sys/kernel/shmmax),超限会导致 PostgreSQL 启动失败并报错 could not create shared memory segment。
-
shared_buffers建议设为物理内存的 25% 左右(但不超过 8GB),再大收益极小且增加 checkpoint 压力 -
effective_cache_size是优化器用的统计值,不是真实分配,设太高会让优化器误判“磁盘读很快”,从而选错执行计划(比如放弃索引走 seq scan) - 修改
shared_buffers同样需要重启,且首次启动会清空 OS page cache,可能引发短暂性能抖动
真正安全的调优路径是分层控制
靠单个参数硬扛并发不现实。关键是在连接层、查询层、系统层做隔离和限制:
- 用 PgBouncer 或 pgbouncer-rr 做连接池,把
max_connections控制在 100–200,让池内连接复用 - 用
statement_timeout和lock_timeout防住长查询和锁等待雪崩 - 用
resource_queue(通过 pg_partman 或第三方扩展)或原生ALTER ROLE … SET对不同业务角色设不同work_mem - 监控
pg_stat_activity和/proc/中的/status VmRSS,比看free -h更准
最常被忽略的一点:PostgreSQL 的内存压力不会立刻表现为查询失败,而是先悄悄退化成磁盘排序、buffer miss、checkpoint 频繁——等看到 OOM,往往已经晚了两轮监控周期。










