1. 问题现象与初步排查那天早上刚到公司就接到报警短信生产环境的PostgreSQL服务挂了。登录服务器一看果然5432端口没有监听。尝试用pg_ctl启动直接报错$ pg_ctl start waiting for server to start....2023-06-15 09:23:45 CST FATAL: could not create shared memory segment: No space left on device 2023-06-15 09:23:45 CST DETAIL: Failed system call was shmget(key5432001, size56, 03600). stopped waiting pg_ctl: could not start server更诡异的是原本应该存在的postmaster.pid文件也消失了。这属于典型的共享内存不足 PID文件异常复合型故障需要分步骤排查。重要提示生产环境遇到数据库启动失败时切勿盲目重启服务应先备份数据目录和日志文件。2. 共享内存问题深度解析2.1 PostgreSQL共享内存机制PostgreSQL使用System V共享内存SHM进行进程间通信主要用途包括共享缓冲区shared_buffersWAL缓冲区wal_buffers锁空间lock_space其他后台进程通信通过ipcs -m命令可以看到当前系统的共享内存段$ ipcs -m ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x0052e001 65536 postgres 600 8388608 2 dest 0x0052e002 98305 postgres 600 16777216 2 dest2.2 常见错误原因系统限制不足# 查看当前限制 $ sysctl kernel.shmall kernel.shmall 2097152 $ sysctl kernel.shmmax kernel.shmmax 33554432残留内存段未释放# 查找属于postgres的残留内存 $ ipcs -m | grep postgres 0x0052e001 65536 postgres 600 8388608 0权限问题$ ls -l /dev/shm drwx------ 2 postgres postgres 40 Jun 15 09:00 postgresql2.3 解决方案实操步骤1清理残留共享内存# 查找所有postgres相关的共享内存 $ ipcs -m | grep postgres | awk {print $2} | xargs -I {} ipcrm -m {} # 验证清理结果 $ ipcs -m | grep postgres步骤2调整系统参数需root权限# 临时修改 echo 17179869184 /proc/sys/kernel/shmmax echo 4194304 /proc/sys/kernel/shmall # 永久生效 echo kernel.shmmax17179869184 /etc/sysctl.conf echo kernel.shmall4194304 /etc/sysctl.conf sysctl -p步骤3验证PostgreSQL配置检查postgresql.conf中shared_buffers 4GB # 建议物理内存的25% wal_buffers 16MB # 建议shared_buffers的1/323. PID文件丢失问题排查3.1 PID文件的作用postmaster.pid文件记录着主进程PID第一行数据目录路径第二行启动时间第三行端口号第四行共享内存ID第五行文件通常位于$PGDATA/postmaster.pid示例内容12345 /var/lib/postgresql/12/main 1662345678 5432 54320013.2 文件丢失的可能原因异常关机服务器突然断电导致文件未正确删除手动误删管理员清理文件时误操作磁盘空间满导致文件写入失败权限问题PostgreSQL进程无写权限3.3 恢复方案方案1安全模式启动$ pg_ctl start -D /path/to/data -o -o --allow-sysid-override方案2手动创建PID文件# 查找正在运行的postgres进程 $ ps aux | grep postgres | grep -v grep # 假设找到主进程PID为12345 $ echo 12345 $PGDATA/postmaster.pid $ echo /var/lib/postgresql/12/main $PGDATA/postmaster.pid $ date %s $PGDATA/postmaster.pid $ echo 5432 $PGDATA/postmaster.pid $ echo 5432001 $PGDATA/postmaster.pid # 修改权限 $ chown postgres:postgres $PGDATA/postmaster.pid $ chmod 644 $PGDATA/postmaster.pid4. 完整故障修复流程4.1 实际操作步骤记录检查系统状态free -h df -h ipcs -m清理残留资源pkill -9 postgres ipcs -m | grep postgres | awk {print $2} | xargs -I {} ipcrm -m {}调整内核参数sysctl -w kernel.shmmax17179869184 sysctl -w kernel.shmall4194304启动PostgreSQLsu - postgres pg_ctl start -D /var/lib/postgresql/12/main -l /var/log/postgresql/startup.log验证启动状态psql -U postgres -c SELECT version();4.2 关键日志分析检查日志/var/log/postgresql/postgresql-12-main.log发现LOG: database system was interrupted; last known up at 2023-06-15 02:00:45 CST LOG: could not create shared memory segment: No space left on device FATAL: could not create shared memory segment: No space left on device5. 预防措施与优化建议5.1 监控配置共享内存监控脚本#!/bin/bash SHM_USAGE$(ipcs -m | grep postgres | wc -l) if [ $SHM_USAGE -gt 10 ]; then echo 警告PostgreSQL共享内存段过多 | mail -s SHM警报 adminexample.com fi添加到crontab*/30 * * * * /path/to/monitor_shm.sh5.2 参数优化建议postgresql.conf优化shared_buffers 4GB work_mem 16MB maintenance_work_mem 256MB系统限制调整# /etc/security/limits.conf postgres soft memlock unlimited postgres hard memlock unlimited5.3 高可用方案考虑配置Patronietcd实现自动故障转移scope: postgres-cluster name: node1 restapi: listen: 0.0.0.0:8008 connect_address: 192.168.1.101:8008 etcd: hosts: - 192.168.1.101:2379 - 192.168.1.102:2379 - 192.168.1.103:23796. 疑难问题排查指南6.1 常见错误代码速查表错误代码可能原因解决方案FATAL: could not create shared memory segment共享内存不足清理残留内存或增加shmmaxWARNING: semaphore PostgreSQL still exists信号量未释放ipcrm -sPANIC: could not flush dirty data: No space left on device磁盘空间满清理磁盘或扩展存储6.2 高级诊断技巧使用strace跟踪系统调用strace -f -o /tmp/postgres_strace.log /usr/lib/postgresql/12/bin/postgres -D /var/lib/postgresql/12/main检查信号量状态ipcs -s ipcrm -s semid验证共享内存配置postgres -D $PGDATA --shared-buffers4GB --wal-buffers16MB --debug这次故障让我深刻认识到PostgreSQL的共享内存管理比想象中更复杂。特别是在频繁启停服务的场景下一定要确保资源被正确释放。后来我们在Ansible部署脚本中增加了自动清理步骤再没出现过类似问题。