Get Hands-on with Amazon EKS - Workshop Event Series
Whether you're taking your first steps with Kubernetes or you're an experienced practitioner looking to sharpen your skills, our Amazon EKS workshop series delivers practical, real-world experience that moves you forward. Learn directly from AWS solutions architects and EKS specialists through hands-on sessions designed to build your confidence with Kubernetes. Register now and start building with Amazon EKS!
为什么我在 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; -
根据前面命令的输出比较数据库的已用大小和实际大小。如果差异很大,则孤立文件可能正在占用存储空间。

