一台 8 核 16G 的 CentOS 7 跑 PostgreSQL 12,数据盘写满时业务报 could not extend file No space left on device,删掉日志腾出 30G 之后同样的报错还在。

一开始怀疑是「临时文件在 /tmp 生成并占满,排序和哈希操作全部失败」,查了一圈,方向不对。

原因不止一个,得分开看。写事务已经进入失败状态,连接池里的会话一直复用同一个错误,重试也被立刻打回。少数情况下是WAL 目录写满后检查点无法推进,数据文件即使有空间也写不进去。

少数情况下是磁盘满时产生的部分写页面留在页缓存里,进程没重启就一直带着坏页。

第一件事是确认空间和 WAL 状态都正常

df -h /data /tmp && du -sh /data/pg_wal

随后看当前失败会话与检查点情况

psql -c 'select pid,state,wait_event from pg_stat_activity'

再往下重建连接池里的会话让错误状态清掉

systemctl restart pgbouncer && psql -c 'checkpoint'

末了核对写入是否恢复并观察下次检查点

psql -c "create table t_probe(id int)" && psql -c 'select pg_current_wal_lsn()'

改完先别撤,确认这几项。建表语句执行成功,pg_stat_activity 里没有报错状态的会话,pg_wal 目录不再持续增长,业务写入恢复且错误日志不再出现 No space left。

容易忽略的是,数据库在磁盘满之后不能只清空间,必须让失败会话和坏页一起清掉;WAL 单独放盘能避免一次日志写满把整个实例拖死。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。

作者 9823189