K8S环境PostgreSQL主从POD停测后缓存未清理引发崩溃问题咨询
PostgreSQL 压测后缓存不释放导致OOM问题分析
注:pg_top输出中的
FATAL: role "root" does not exist是执行命令的用户为root、无对应PostgreSQL角色导致的报错,不影响内存、CPU等系统指标的有效性。
核心原因梳理
- PostgreSQL 共享内存设计特性:你配置的
shared_buffers = 40GB是PostgreSQL启动时就向操作系统申请的固定共享内存段,属于PG自己管理的缓存区域,只要PG进程不重启,这部分内存不会主动释放回操作系统,是正常的设计逻辑而非内存泄漏。压测过程中大量热数据会被加载到该区域,压测停止后无新请求也会被PG默认保留,避免下次访问需要重新读盘。 - 操作系统页缓存未触发回收:pg_top输出的
96G cached是Linux内核管理的页缓存,用于缓存最近访问的磁盘文件数据提升读写性能,默认只有在系统可用内存不足时才会自动淘汰冷数据。你当前停止压测后系统还有64G空闲内存,所以内核不会主动清理这部分缓存。 - K8S 资源配置不合理触发OOM:你给PostgreSQL POD配置的内存上限为110Gi,而PG自身shared_buffers已占用40G,叠加操作系统页缓存、PG连接私有内存、运算临时内存的占用,很容易触碰到K8S的内存限制阈值,触发cgroup OOM Killer杀掉PG进程,最终导致后端服务崩溃。
配置不合理的叠加因素
max_connections = 10000配置过高:PostgreSQL每个连接会占用固定的私有内存,即便空闲也不会释放,压测如果跑满连接,单连接内存累加值会远超预期,PG官方建议该参数不要超过1000,更高并发场景建议用pgbouncer做连接池代理。- 内存预留空间不足:你配置的
effective_cache_size = 90GB是PG查询优化器认为可用的缓存总大小,而POD内存上限仅110Gi,扣除PG自身占用后留给操作系统、页缓存的冗余空间不足,进一步提升了OOM概率。 work_mem = 6MB的潜在风险:每个数据库连接执行排序、哈希聚合等操作时,最多可申请6MB临时内存,压测高并发场景下大量并行运算的内存总占用可能超出预期,叠加其他内存开销更容易触顶。
修复与优化建议
临时修复
- 执行
echo 3 > /proc/sys/vm/drop_caches手动清理操作系统冷页缓存,该操作不会影响PostgreSQL的正常运行,可快速降低内存占用。 - 不要盲目重启PostgreSQL进程,会导致shared_buffers内的热数据全部丢失,重启后业务请求直接打磁盘可能引发慢查询雪崩。
长期优化
- 下调
max_connections到1000以内,前端部署pgbouncer连接池代理数据库连接,大幅降低连接本身的内存开销。 - 上调POD内存limit到128Gi及以上,预留足够的冗余空间给页缓存、临时运算内存使用,避免触碰到cgroup内存阈值。
- 调整Linux内核参数
vm.min_free_kbytes,让系统在可用内存低于阈值时提前触发页缓存回收,避免内存占用直接触顶。 - 如果需要严格控制内存占用,可开启cgroup内存统计的页缓存计数,配合内核回收策略实现内存占用的动态调整。
内容的提问来源于stack exchange,提问作者JAN
相关产品推荐
相关产品推荐

