/dev/shm 空间耗尽会导致 Redis 和 PostgreSQL 崩溃,因其 RDB 快照、并行查询、WAL 共享内存等依赖该 tmpfs 文件系统;默认 64MB 容易被占满,引发 ENOSPC 错误,造成服务拒绝连接或退出。

为什么 /dev/shm 满了会让 Redis 和 PostgreSQL 崩溃
Redis 默认用 fork() 做 RDB 快照,PostgreSQL 的并行查询、WAL 共享内存、甚至某些客户端连接(如使用 unix_socket_directories 时的 socket 文件)都可能依赖 /dev/shm。它本质是基于 tmpfs 的内存文件系统,默认大小通常只有 64MB(取决于内核版本和发行版),而 fork 时子进程会复制父进程的虚拟内存页(写时复制),但某些共享内存段(如 PostgreSQL 的 shared_memory_type = mmap 或 Redis 的 AOF rewrite 过程中临时缓冲)会直接在 /dev/shm 创建文件——一旦空间耗尽,open() 或 shm_open() 返回 ENOSPC,服务就卡在初始化或 checkpoint 阶段,表现为拒绝新连接、主从同步中断、甚至进程直接退出。
检查 /dev/shm 是否真成瓶颈
别只看 df -h /dev/shm,那只是 tmpfs 总大小;更要确认实际被哪些进程占用了:
- 运行
ls -l /dev/shm/,重点关注以redis、PostgreSQL、pg_、sem.、shmem.开头的文件 - 用
find /dev/shm -type f -size +1M -ls找大文件 - 查 Redis 日志是否含
Failed to open the temp file for AOF rewrite或Cannot allocate memory - 查 PostgreSQL 日志是否含
could not resize shared memory segment或out of memory(注意:这不一定是物理内存不足,可能是 shm 限额)
临时扩容与永久配置 /dev/shm 大小
临时改法立竿见影但重启失效;永久改法需配合挂载参数,且必须避开 systemd-tmpfiles 的覆盖逻辑:
- 临时扩容(立刻生效):
sudo mount -o remount,size=2G /dev/shm - 永久生效(推荐):编辑
/etc/fstab,把原tmpfs /dev/shm tmpfs defaults 0 0改成tmpfs /dev/shm tmpfs defaults,size=2G 0 0,然后sudo mount -o remount /dev/shm - 避免 systemd 干扰:确保
/usr/lib/tmpfiles.d/tmp.conf或/etc/tmpfiles.d/*.conf中没有对/dev/shm的d或Z类型定义(它们会重置权限和大小)
更治本:让 Redis 和 PostgreSQL 少用 /dev/shm
扩容只是兜底,关键要减少对它的依赖:
- Redis:设
stop-writes-on-bgsave-error no只是掩盖问题;真正有效的是关掉 AOF(如果业务允许),或把appendfilename改到普通磁盘路径(AOF 文件本身不走 shm,但 rewrite 临时文件会);升级到 7.0+ 后可用replica-announce-ip+replica-announce-port避免某些 shm 通信路径 - PostgreSQL:将
shared_memory_type从默认的mmap改为sysv(需重启),它用 System V IPC 而非/dev/shm;同时调低max_connections和work_mem,减少共享内存总需求 - 通用:禁用不需要的扩展(如
pg_stat_statements在高并发下会频繁写 shm)、定期清理僵尸 socket 文件(find /dev/shm -name "PostgreSQL.*" -mmin +60 -delete)
最常被忽略的是:容器环境里 /dev/shm 默认只有 64MB 且不会继承宿主机配置,docker run --shm-size=2g 或 Kubernetes 的 securityContext.shmSize 必须显式设置。










