外观
PostgreSQL 磁盘空间不足问题
磁盘空间不足现象
1. 系统层面
- 操作系统告警:磁盘使用率超过阈值
- 命令行输出:使用
df -h查看磁盘使用率达到100% - 系统日志:包含磁盘空间不足的错误信息
2. 数据库层面
- 连接失败:无法建立新连接
- 写入失败:无法插入或更新数据
- 错误信息:
FATAL: could not write to file "pg_xlog/xlogtemp.1234": No space left on deviceERROR: could not extend file "base/12345/67890": No space left on deviceWARNING: could not write statistics file "pg_stat_tmp/global.stat": No space left on device
磁盘空间分析
1. 查看磁盘使用率
bash
# 查看所有磁盘分区的使用率
df -h
# 查看特定目录的磁盘使用情况
du -sh /var/lib/postgresql/*
# 查看PostgreSQL数据目录的详细使用情况
du -sh /var/lib/postgresql/15/main/*
# 按照大小排序,查看前10个最大的文件或目录
du -a /var/lib/postgresql/15/main | sort -n -r | head -n 102. 分析PostgreSQL数据目录结构
bash
# PostgreSQL数据目录结构
# 主要目录说明:
# - base/:用户数据库文件
# - pg_xact/:事务提交日志
# - pg_wal/:预写式日志(WAL)
# - pg_stat_tmp/:临时统计数据
# - pg_logical/:逻辑复制相关文件
# - pg_replslot/:复制槽文件
# - pg_tblspc/:表空间链接3. 查看数据库大小
sql
-- 查看所有数据库的大小
SELECT datname, pg_size_pretty(pg_database_size(datname)) AS size
FROM pg_database
ORDER BY pg_database_size(datname) DESC;
-- 查看特定数据库的大小
SELECT pg_size_pretty(pg_database_size('mydb'));
-- 查看数据库中表的大小(包括索引)
SELECT schemaname, tablename, pg_size_pretty(pg_total_relation_size(schemaname || '.' || tablename)) AS size
FROM pg_tables
WHERE schemaname = 'public'
ORDER BY pg_total_relation_size(schemaname || '.' || tablename) DESC;
-- 查看数据库中索引的大小
SELECT schemaname, indexname, tablename, pg_size_pretty(pg_relation_size(schemaname || '.' || indexname)) AS size
FROM pg_indexes
WHERE schemaname = 'public'
ORDER BY pg_relation_size(schemaname || '.' || indexname) DESC;4. 查看WAL日志大小
bash
# 查看WAL日志目录大小
du -sh /var/lib/postgresql/15/main/pg_wal
# 查看WAL日志文件数量
ls -la /var/lib/postgresql/15/main/pg_wal | grep -v "\." | wc -lsql
-- 查看WAL保留策略
SHOW wal_keep_size;
SHOW max_wal_size;
SHOW min_wal_size;
-- 查看复制槽状态(可能导致WAL堆积)
SELECT slot_name, slot_type, active, pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) AS wal_diff
FROM pg_replication_slots;磁盘空间不足解决措施
1. 紧急释放空间
清理临时文件
bash
# 清理PostgreSQL临时统计文件
sudo rm -f /var/lib/postgresql/15/main/pg_stat_tmp/*
# 清理操作系统临时文件
sudo rm -f /tmp/*清理WAL日志(仅在紧急情况下)
bash
# 注意:此操作非常危险,可能导致数据丢失,仅在无法启动数据库时使用
# 确保已备份重要数据
# 清理旧的WAL日志文件
sudo rm -f /var/lib/postgresql/15/main/pg_wal/00000001000000000000000*清理无用的复制槽
sql
-- 删除不活跃的复制槽
SELECT pg_drop_replication_slot('inactive_slot');2. 长期解决方案
扩展磁盘空间
- 添加新的磁盘分区
- 扩展现有分区
- 迁移到更大的存储设备
优化数据库存储
sql
-- 清理表中的死元组
VACUUM ANALYZE table_name;
-- 彻底清理表(需要排它锁)
VACUUM FULL ANALYZE table_name;
-- 重建索引(释放空间)
REINDEX TABLE table_name;
-- 删除无用的表
DROP TABLE unused_table;
-- 删除无用的索引
DROP INDEX unused_index;
-- 清理大表中的历史数据
DELETE FROM large_table WHERE created_at < '2023-01-01';
VACUUM ANALYZE large_table;配置自动清理
sql
-- 调整自动清理参数
ALTER SYSTEM SET autovacuum = 'on';
ALTER SYSTEM SET autovacuum_vacuum_scale_factor = '0.05'; -- 5%的行变更触发清理
ALTER SYSTEM SET autovacuum_analyze_scale_factor = '0.02'; -- 2%的行变更触发分析
ALTER SYSTEM SET autovacuum_max_workers = '3'; -- 最大清理工作线程数
ALTER SYSTEM SET maintenance_work_mem = '256MB'; -- 清理时使用的内存
-- 重新加载配置
SELECT pg_reload_conf();配置WAL日志保留策略
sql
-- 调整WAL日志大小限制
ALTER SYSTEM SET max_wal_size = '1GB';
ALTER SYSTEM SET min_wal_size = '512MB';
-- 调整WAL保留时间(如果使用归档)
-- 注意:这取决于归档设置和备份策略
-- 重新加载配置
SELECT pg_reload_conf();磁盘空间监控与告警
1. 系统层面监控
bash
# 使用iostat监控磁盘I/O和使用率
iostat -x 1
# 使用du定期检查目录大小
# 可以编写脚本定期检查并告警2. 数据库层面监控
sql
-- 监控数据库大小变化
SELECT datname, pg_size_pretty(pg_database_size(datname)) AS size,
pg_size_pretty(pg_database_size(datname) - pg_size_pretty(pg_database_size(datname) FILTER (WHERE datname = datname AND now() - pg_postmaster_start_time() < interval '1 day'))) AS growth
FROM pg_database;
-- 监控表大小变化
CREATE OR REPLACE FUNCTION monitor_table_growth()
RETURNS VOID AS $$
BEGIN
-- 插入表大小信息到监控表
INSERT INTO table_growth_monitor (table_name, size, monitoring_time)
SELECT schemaname || '.' || tablename, pg_total_relation_size(schemaname || '.' || tablename), now()
FROM pg_tables
WHERE schemaname = 'public';
END;
$$ LANGUAGE plpgsql;
-- 每天执行一次监控
SELECT cron.schedule('0 0 * * *', 'SELECT monitor_table_growth();');3. 告警配置
Prometheus + Grafana监控
监控指标:
node_filesystem_avail_bytes:可用磁盘空间node_filesystem_size_bytes:总磁盘空间node_filesystem_free_bytes:空闲磁盘空间node_filesystem_files_free:可用文件数
告警规则:
- 磁盘使用率超过90%时告警
- 可用空间小于10GB时告警
- WAL目录使用率超过80%时告警
Zabbix监控
监控项:
- 磁盘使用率
- 可用磁盘空间
- PostgreSQL数据目录大小
- WAL日志目录大小
触发器:
- 磁盘使用率 > 90%
- 可用磁盘空间 < 10GB
- WAL目录大小 > max_wal_size * 2
磁盘空间管理最佳实践
1. 预防措施
- 定期监控:设置磁盘空间监控和告警
- 合理规划:根据业务增长预测,规划足够的磁盘空间
- 自动清理:配置自动清理策略,定期清理无用数据
- 分区表:对大表使用分区,便于管理和清理历史数据
- 压缩数据:对不常访问的数据进行压缩
2. 备份与恢复
- 定期备份:确保有可靠的备份策略
- 测试恢复:定期测试备份恢复,确保数据可恢复
- 增量备份:结合全量备份和增量备份,减少备份空间占用
3. 存储优化
- 使用表空间:将不同类型的数据存储在不同的磁盘上
- 优化WAL策略:根据业务需求调整WAL保留策略
- 使用压缩备份:使用pg_basebackup的压缩选项
- 清理无用对象:定期清理无用的表、索引和扩展
常见问题(FAQ)
Q1:PostgreSQL磁盘空间不足的常见原因有哪些?
A1:PostgreSQL磁盘空间不足的常见原因包括:
- 数据量增长过快
- WAL日志堆积(复制槽未清理、归档失败)
- 临时文件过多
- 自动清理不及时,导致死元组堆积
- 索引膨胀
- 表空间配置不当
Q2:如何查看PostgreSQL数据目录的使用情况?
A2:可以使用以下命令查看:
bash
du -sh /var/lib/postgresql/15/main/*
du -a /var/lib/postgresql/15/main | sort -n -r | head -n 10Q3:如何安全地清理PostgreSQL磁盘空间?
A3:安全清理PostgreSQL磁盘空间的方法:
- 先分析空间使用情况,找出占用空间最大的文件或目录
- 使用VACUUM和VACUUM FULL清理死元组
- 重建膨胀的索引
- 清理无用的表和索引
- 调整WAL保留策略
- 清理不活跃的复制槽
Q4:如何防止PostgreSQL磁盘空间不足?
A4:防止PostgreSQL磁盘空间不足的措施:
- 设置磁盘空间监控和告警
- 配置自动清理策略
- 定期清理历史数据
- 使用分区表管理大表
- 合理规划存储容量
- 定期备份和清理备份文件
Q5:WAL日志堆积的原因是什么?如何解决?
A5:WAL日志堆积的常见原因:
- 复制槽不活跃或配置错误
- 归档失败
- max_wal_size设置过大
解决方法:
- 删除不活跃的复制槽
- 检查归档配置,确保归档成功
- 调整max_wal_size参数
- 手动清理旧的WAL日志(仅在紧急情况下)
