用心打造
VPS知识分享网站

PostgreSQL报could not resize shared memory segment,容器共享内存处理指南

本文于 2026-09-11 08:44 更新,部分内容具有时效性,如有失效,请留言

PostgreSQL执行查询、建索引或维护任务时,如果报 could not resize shared memory segment 并带有 No space left on device,在容器环境里常见原因不是数据盘已满,而是 /dev/shm 这类动态共享内存空间不足。

先区分主机内存、数据卷磁盘与容器共享内存三个不同资源。 盲目清理数据库文件既危险,也通常无法解决这条错误。

PostgreSQL容器因dev shm共享内存容量不足而无法扩展内存段的示意图

先确认错误与触发操作

保留PostgreSQL日志中的完整错误、段名称、请求大小和SQL类型,再检查当前共享内存实现与并行设置:

SHOW dynamic_shared_memory_type;
SHOW max_parallel_workers_per_gather;
SHOW max_parallel_maintenance_workers;

PostgreSQL官方文档说明,动态共享内存可使用POSIX、System V、Windows或mmap等实现,具体可用值与平台有关。Linux上的POSIX动态共享内存通常会反映到 /dev/shm,并行查询在启动额外工作进程时可能申请更多空间。

还要记录故障是普通SELECT、CREATE INDEX、VACUUM还是其他维护任务触发。不要只凭错误文本永久关闭所有并行能力;应先确认是容量不足、inode不足、挂载异常还是并发工作负载过高。

检查容器内的/dev/shm

在PostgreSQL实际运行的容器中检查容量、使用量、inode和挂载类型:

docker exec postgres df -h /dev/shm
docker exec postgres df -i /dev/shm
docker exec postgres mount | grep ' /dev/shm '
docker exec postgres ls -lah /dev/shm

再从宿主机读取容器配置的共享内存字节数:

docker inspect --format '{{.HostConfig.ShmSize}}' postgres

Docker官方CLI文档说明,未指定 --shm-size 时容器默认共享内存大小为64m。不同编排平台可能使用不同默认值和配置入口,不能把64m当成所有容器环境的统一结论。

0 有空闲空间,不能证明 1 有空间。 tmpfs有独立容量限制;inode耗尽或异常残留对象也会导致类似失败。

临时降低并行度用于止血

如果证据表明错误由并行查询触发,可在受影响会话中临时禁用单条查询的并行工作进程:

SET max_parallel_workers_per_gather = 0;

并行维护任务可在对应会话评估:

SET max_parallel_maintenance_workers = 0;

PostgreSQL文档明确指出,把 max_parallel_workers_per_gather 设为0会禁用并行查询。并行工作进程会增加CPU、内存和I/O资源使用,实际总消耗可能显著高于单进程计划。

这只是缩小故障影响的临时措施,可能让查询或建索引明显变慢。 不要未经性能评估就把全局参数永久改成0,也不要在业务高峰执行 EXPLAIN ANALYZE 去复现重型SQL,因为它会真正运行查询。

为Docker或Compose设置合理shm_size

使用 docker run 创建容器时,可按工作负载设置共享内存上限:

docker run --name postgres --shm-size=512m ...

Docker Compose可在服务定义中使用 shm_size

services:
  postgres:
    image: postgres:17
    shm_size: 512m

数值512m只是演示,不是通用推荐。应根据失败申请大小、并发并行任务和宿主机内存余量确定,并为其他服务保留安全边界。修改shm_size通常需要重建容器,单纯restart不会改变创建时的HostConfig。

重建前必须确认数据库数据位于持久卷或受控存储,并验证备份。不要执行会删除命名卷的命令,也不要把空目录误挂载到原数据目录。

评估宿主机与数据库资源边界

扩大 /dev/shm 上限不会预先占满等量物理内存,但实际使用仍受宿主机内存、容器内存限制和并发负载约束。若容器本身接近内存上限,单纯放大共享内存可能把问题变成OOM终止。

同时查看容器资源与宿主机内存:

docker stats --no-stream postgres
docker inspect -f '{{.HostConfig.Memory}}' postgres
free -h

需要在隔离环境中复现并行查询时,可用 萤光云 建立临时数据库主机;要对比不同地区节点的容器资源行为,也可使用 LightNode 部署测试实例。只能使用脱敏数据或可重建样本,不能复制生产数据库凭据。

重建后的验收标准

容器重建后,先确认新配置确实生效:

docker inspect --format '{{.HostConfig.ShmSize}}' postgres
docker exec postgres df -h /dev/shm
docker ps --filter name=postgres

然后在可控时段重新执行原SQL或维护任务,观察PostgreSQL日志、 /dev/shm 峰值、容器内存和退出状态。若之前临时修改过会话并行度,还要分别测试正常并行设置与降级设置。

验收通过应同时满足原操作成功、日志不再出现共享内存扩容错误、 0 保有合理余量、容器没有OOM或重启,并且数据卷与数据库一致性检查正常。

FAQ

No space left on device一定是数据库磁盘满了吗?

不一定。错误对象若是共享内存段,应重点检查 /dev/shm;数据目录磁盘、tmpfs和inode是不同资源。

把shm_size设得越大越好吗?

不是。应按并发和查询需求设置,同时考虑宿主机与容器内存上限。过大不能修复SQL或并发设计问题。

可以改dynamic_shared_memory_type绕过吗?

该参数可选值受平台影响,且mmap并非默认并可能增加I/O。除非有充分测试与明确运维理由,不应把更换实现当成首选修复。

温馨提示

共享内存故障常发生在高负载或并行维护期间。先用会话级降并行保护业务,再通过容量证据确定shm_size,并在有备份、可回退的前提下重建容器。

赞(0)
未经允许不得转载;国外VPS测评网 » PostgreSQL报could not resize shared memory segment,容器共享内存处理指南
分享到