为什么我在 Amazon RDS for PostgreSQL 上收到“No space left on device”(设备上没有剩余空间)或“DiskFull”错误?
我有一个小型 Amazon Relational Database Service (Amazon RDS) for PostgreSQL 数据库。数据库实例的可用存储空间正在减少,我收到以下错误: "Error message: PG::DiskFull: ERROR: could not extend file "base/16394/5139755": No space left on device.HINT: Check free disk space."
解决方案
**注意:**如果您的工作负载是可预测的,请为您的实例激活存储自动扩展功能。借助存储自动扩展功能,当可用数据库空间不足时,Amazon RDS 会自动扩展您的存储空间。
要监控您的存储空间,请查看 Amazon CloudWatch 指标 FreeStorageSpace。为可用存储空间设置 CloudWatch 警报,以便在空间开始减少时收到通知。如果您收到警报,请检查以下使用 Amazon RDS 数据库实例存储的资源:
- 由 PostgreSQL 事务创建的临时表或文件
- 数据文件
- 预写日志 (WAL)
- 复制槽
- 数据库日志,例如保留时间过长的错误文件
- 支持 RDS 数据库实例一致性状态的其他数据库或 Linux 文件
如果您的数据库实例使用的存储空间超过预期的存储空间,请执行以下故障排除操作。
检查数据库日志文件的大小
默认情况下,Amazon RDS for PostgreSQL 错误日志文件的留存时间值为 4,320 分钟(三天)。由于工作负载较高或日志记录过多,大型日志文件可能会占用更多空间。要更改系统日志的留存期,请使用与您的数据库实例关联的数据库参数组中的 rds.log_retention_period 参数。例如,如果您将该值设置为 1,440,则 Amazon RDS 会将日志保留一天。有关详细信息,请参阅 RDS for PostgreSQL 数据库日志文件。
要减少过多的日志记录,请更改数据库参数组中的错误报告和日志记录参数。此操作会减小日志文件的大小。有关详细信息,请参阅 PostgreSQL 网站上的 19.8 Error reporting and logging。
检查是否有临时文件
临时文件是 Amazon RDS 存储在每个后端或会话连接中的文件。Amazon RDS 使用这些文件作为资源池。要查看临时文件统计信息,请运行以下命令:
psql=> SELECT datname, temp_files AS "Temporary files",temp_bytes AS "Size of temporary files" FROM pg_stat_database ;
**重要事项:**pg_stat_database 视图中的 temp_files 和 temp_bytes 列收集聚合统计信息。只有在立即关闭、服务器崩溃或时间点故障恢复 (PITR) 之后,Amazon RDS 才会重置这些计数器。因此,最佳做法是监控这些文件数量和大小的增长,而不仅仅是查看输出。
Amazon RDS 会为排序、哈希和临时查询结果创建临时文件。要追踪临时表或文件的创建,请在自定义参数组中将 log_temp_files 设置为 0 以记录所有临时文件信息。默认情况下,log_temp_files 设置为 -1,因此 Amazon RDS 不记录临时文件。如果您将 log_temp_files 设置为正值,则 Amazon RDS 仅记录等于或大于该千字节数的文件。
在查询中使用 EXPLAIN ANALYZE 来查看磁盘排序。在日志输出中,检查您的查询创建的临时文件的大小。有关详细信息,请参阅使用 work_mem 调整 PostgreSQL 中的排序操作。
检查事务日志磁盘使用量是否持续增加
检查 TransactionLogsDiskUsage 指标,以查看事务 WAL 使用的磁盘空间。事务日志磁盘使用量增加可能是由于以下原因造成的:
- 生成额外 WAL 的写入和更新操作导致数据库高负载
- 相同 AWS 区域中副本的流式传输只读副本延迟,或存储已满状态的只读副本
- 复制槽
AWS Database Migration Service (AWS DMS) 可能会创建复制槽作为逻辑解码的一部分。对于逻辑复制,rds.logical_replication 槽参数设置为 1。复制槽会保留 WAL 文件,直到外部使用者使用这些文件为止。示例使用者包括 pg_recvlogical、提取、转换、加载 (ETL) 作业以及 AWS DMS。
如果您将 rds.logical_replication 设置为 1,则 Amazon RDS 会设置 wal_level、max_wal_senders、max_replication_slots 和 max_connections 参数。这些参数更改可能会增加 WAL 的生成。最佳做法是仅在使用逻辑槽时设置 rds.logical_replication 参数。如果保留的 WAL 文件没有使用者,则事务日志磁盘使用量会增加,可用存储空间会持续减少。
要检查复制槽是否存在及其大小,请运行以下查询:
-
PostgreSQL v9:
psql=> SELECT slot_name, pg_size_pretty(pg_xlog_location_diff(pg_current_xlog_location(),restart_lsn)) AS replicationSlotLag, active FROM pg_replication_slots ;
-
PostgreSQL v10 及更高版本:
psql=> SELECT slot_name, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(),restart_lsn)) AS replicationSlotLag, active FROM pg_replication_slots ;
输出示例:
slot_name | replicationslotlag | active---------------------------------------------------------------+--------------------+-------- xc36ujql35djp_00013322_907c1e0a_9f8b_4c13_89ea_ef0ea1cf143d | 129 GB | f 7pajuy7htthd7sqn_00013322_a27bcebf_7d0f_4124_b336_92d0fb9f5130 | 704 MB | t zp2tkfo4ejw3dtlw_00013322_03e77862_689d_41c5_99ba_021c8a3f851a | 624 MB | t
活动状态设置为 f (false) 的复制槽未被使用。在此示例中,xc36ujql35djp_00013322_907c1e0a_9f8b_4c13_89ea_ef0ea1cf143d 槽的活动状态为 f。此槽未被有效使用,但使用了 129 GB 的事务文件。
要删除未使用的槽,请运行以下查询:
psql=> SELECT pg_drop_replication_slot('YOUR_SLOTNAME');
**注意:**请将 YOUR_SLOTNAME 替换为槽名称。
输出示例:
psql=> SELECT pg_drop_replication_slot('xc36ujql35djp_00013322_907c1e0a_9f8b_4c13_89ea_ef0ea1cf143d');
如果您不再需要的 AWS DMS 任务是使用者,请删除该任务并手动删除复制槽。
检查跨区域或同区域只读副本的状态
**注意:**只有当同区域只读副本在 PostgreSQL 14.1 或更高版本上运行时,您才能对这些副本使用以下解决方法。
当您使用跨区域或同区域只读复制时,Amazon RDS 会在主实例上创建物理复制槽。只读副本故障可能会影响主数据库实例上的存储空间。当未在只读副本中复制 WAL 文件时,将会出现这种情况。检查 OldestReplicationSlotLag 和 TransactionLogsDiskUsage 指标,以确定延迟最大的副本落后了多远。您还可以查看 WAL 数据使用了多少存储空间。
要检查只读副本的状态,请运行以下查询:
psql=> SELECT * FROM pg_replication_slots;
有关 pg_replication_slots 的详细信息,请参阅 PostgreSQL 网站上的 52.19 pg_replication_slots。如果输出的活动状态设置为 f,则该槽不用于复制。
您还可以使用源实例上的视图 pg_stat_replication 来查看复制的统计信息。有关详细信息,请参阅 PostgreSQL 网站上的 Table 27.14. pg_stat_replication view。
检查死行是否出现膨胀或被不当移除
在标准的 PostgreSQL 操作中,PostgreSQL 不会从表中移除用户删除或 UPDATE 使其过时的死行(元组)。对于多版本并发控制 (MVCC) 实现,当您执行 DELETE 操作时,该行不会立即从数据文件中移除。相反,PostgreSQL 会在标头中设置 xmax 字段,以将该行标记为已删除。首先更新标记要删除的行,然后执行插入操作。这样可以在不同事务之间以最少的锁定进行并发。因此,作为 MVCC 流程的一部分,PostgreSQL 会保留不同的行版本。
未清理的死行会保留在数据文件中,但对事务来说仍然不可见。这些行可能会导致磁盘空间问题。如果一个表有很多 DELETE 和 UPDATE 操作,则死元组可能会占用大量的磁盘空间(膨胀)。
请使用 VACUUM 操作来释放死元组使用的存储空间。请注意,VACUUM 不会将可用存储空间释放到文件系统。要将存储空间释放到文件系统,请使用 VACUUM FULL。请注意,当您运行 VACUUM FULL 时,PostgreSQL 会对该表应用访问独占锁。此方法需要额外的磁盘空间,因为 VACUUM FULL 会写入新的表副本,并且在操作完成之前不会释放现有副本。最佳做法是仅在必须从表中回收大量空间时使用 VACUUM FULL。对经常更新的表执行定期 vacuum 或 autovacuum 操作也是一种最佳做法。有关详细信息,请参阅 PostgreSQL 网站上的 VACUUM。
要检查死元组的估计数量,请使用 pg_stat_all_tables 视图。有关详细信息,请参阅 PostgreSQL 网站上的 Table 27.29. pg_stat_all_tables view。在下面的示例表中,n_dead_tup 记录中有 1,999,952 个死元组:
psql => SELECT * FROM pg_stat_all_tables WHERE relname='test'; -[ RECORD 1 ]-------+------------------------------ relid | 16395 schemaname | public relname | test seq_scan | 3 seq_tup_read | 5280041 idx_scan | idx_tup_fetch | n_tup_ins | 2000000 n_tup_upd | 0 n_tup_del | 3639911 n_tup_hot_upd | 0 n_live_tup | 1635941 n_dead_tup | 1999952 n_mod_since_analyze | 3999952 last_vacuum | last_autovacuum | 2024-08-16 04:49:52.399546+00 last_analyze | 2024-08-09 09:44:56.208889+00 last_autoanalyze | 2024-08-16 04:50:22.581935+00 vacuum_count | 0 autovacuum_count | 1 analyze_count | 1 autoanalyze_count | 1 psql => VACUUM TEST;
检查是否存在孤立文件
当没有对象指向数据库目录中存在的文件时,就会出现孤立文件。当您的实例存储空间耗尽或引擎在 ALTER TABLE、VACUUM FULL 或 CLUSTER 等操作期间崩溃时,就会出现这种情况。要检查是否存在孤立文件,请完成以下步骤:
-
在每个数据库中登录 PostgreSQL。
-
要获取数据库的已使用大小,请运行以下查询:
psql=> SELECT pg_size_pretty(pg_database_size('DATABASE_NAME'));
**注意:**请将 DATABASE_NAME 替换为您的数据库名称。
-
要获取数据库的实际大小,请运行以下查询:
psql=> SELECT pg_size_pretty(SUM(pg_relation_size(oid))) FROM pg_class;
-
根据前面命令的输出比较数据库的已用大小和实际大小。如果差异很大,则孤立文件可能正在占用存储空间。
相关信息
相关内容
- AWS 官方已更新 2 年前
- AWS 官方已更新 3 个月前