为什么我在 Amazon RDS for PostgreSQL 上收到“No space left on device”(设备上没有剩余空间)或“DiskFull”错误?

3 分钟阅读
0

我有一个小型 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_filestemp_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_levelmax_wal_sendersmax_replication_slotsmax_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 文件时,将会出现这种情况。检查 OldestReplicationSlotLagTransactionLogsDiskUsage 指标,以确定延迟最大的副本落后了多远。您还可以查看 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 会保留不同的行版本。

未清理的死行会保留在数据文件中,但对事务来说仍然不可见。这些行可能会导致磁盘空间问题。如果一个表有很多 DELETEUPDATE 操作,则死元组可能会占用大量的磁盘空间(膨胀)。

请使用 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 TABLEVACUUM FULLCLUSTER 等操作期间崩溃时,就会出现这种情况。要检查是否存在孤立文件,请完成以下步骤:

  1. 在每个数据库中登录 PostgreSQL。

  2. 要获取数据库的已使用大小,请运行以下查询:

    psql=> SELECT pg_size_pretty(pg_database_size('DATABASE_NAME'));

    **注意:**请将 DATABASE_NAME 替换为您的数据库名称。

  3. 要获取数据库的实际大小,请运行以下查询:

    psql=> SELECT pg_size_pretty(SUM(pg_relation_size(oid))) FROM pg_class;
  4. 根据前面命令的输出比较数据库的已用大小和实际大小。如果差异很大,则孤立文件可能正在占用存储空间。

相关信息

使用 Amazon RDS for PostgreSQL 只读副本

自动监控工具