為什麼我在 Amazon RDS for PostgreSQL 上收到「裝置上沒有剩餘空間」或「DiskFull」錯誤?

3 分的閱讀內容
0

我擁有適用於 PostgreSQL 資料庫的 Amazon Relational Database Service (Amazon RDS)。執行個體的可用儲存空間正在減少,我收到下列錯誤: 「錯誤訊息: PG::DiskFull: 錯誤:無法延伸檔案 "base/16394/5139755": 裝置上沒有剩餘空間。提示: 檢查可用的磁碟空間。」 我想要解決 DiskFull 錯誤並預防儲存體問題。

簡短說明

下列各項使用 Amazon RDS 資料庫執行個體儲存體

  • 由 PostgreSQL 交易建立的暫存表或檔案
  • 資料檔案
  • 預先寫入日誌 (WAL 日誌)
  • 複寫插槽
  • 保留時間過長的資料庫日誌 (錯誤檔案)
  • 支援 RDS 資料庫執行個體一致狀態的其他資料庫或 Linux 檔案

解決方案

1.    使用 Amazon CloudWatch,來監控使用 FreeStorageSpace 指標的資料庫儲存空間。為可用儲存空間設定 CloudWatch 警示後,您會在空間開始減少時收到通知。如果您收到警示,請檢閱前面提到的儲存問題原因。

2.    如果您的資料庫執行個體耗用的儲存體仍超出預期,請檢查下列項目:

  • 資料庫日誌檔案的大小
  • 存在暫存檔
  • 不斷增加交易日誌磁碟使用量
  • 複寫插槽:
  • 只有在 PostgreSQL 14.1 及更高版本上執行時,才會由跨區域讀取複本或相同區域讀取複本建立實體複寫插槽
  • 已針對複本或訂閱用戶建立邏輯複寫插槽
  • 膨脹或不當去除無效資料列
  • 存在孤立檔案

3.    當您的工作負載可預測時,啟用執行個體的儲存體自動調整。啟用儲存體自動調整後,當 Amazon RDS 偵測到您的可用資料庫空間不足時,即會自動調整您的儲存體。當適用於下列因素時,Amazon RDS 會為啟用自動調整的資料庫執行個體啟動儲存體修改:

  • 可用空間少於已配置儲存體的 10%。
  • 低儲存狀況持續至少五分鐘。
  • 從對執行個體完成前次儲存體修改或儲存體最佳化至今 (以較長者為準),至少已經過了六個小時。

您可以設定最大儲存臨界值,以設定資料庫執行個體自動調整的限制。如需詳細資訊,請參閱自動管理 Amazon RDS 儲存體自動調整的容量

檢查資料庫日誌檔案的大小

依預設,Amazon RDS for PostgreSQL 錯誤日誌的保留值為 4,320 分鐘 (三天)。由於工作負載較高或日誌過多,大型日誌可能會使用更多空間。您可以使用與資料庫執行個體相關聯的資料庫參數群組中的 rds.log_retention_period 參數變更系統日誌保留期。例如,如果您將值設定為 1440,則日誌會保留一天。如需詳細資訊,請參閱 PostgreSQL 資料庫日誌檔案

此外,您可以變更資料庫參數群組中的錯誤報告和日誌參數,以減少過多的日誌。這反過來會降低日誌檔案大小。如需詳細資訊,請參閱錯誤報告和日誌

檢查暫存檔

暫存檔是每個後端或會話連線儲存的檔案。將這些檔案當作資源儲存區使用。執行類似下列命令,以檢閱暫存檔統計資料:

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) 之後重設。因此,最佳實務是監控這些檔案的數量和大小變化,而不是僅檢視輸出。

針對排序、雜湊或臨時查詢結果建立暫存檔。若要追蹤暫存表或檔案的建立,請在自訂參數群組中設定log_temp_files。此參數控制暫存檔名稱和大小的日誌。如果您將 log_temp_files 值設定為 0,則會記錄所有暫存檔資訊。如果將參數設為正值,則只會記錄等於或大於指定 KB 數量的檔案。預設設定為 -1,停用暫存檔的日誌。

您還可以使用 EXPLAIN ANALYZE 查詢來檢視磁碟排序。檢閱日誌輸出時,您可以看到查詢建立的暫存檔大小。如需詳細資訊,請參閱監控資料庫活動的 PostgreSQL 文件。

檢查交易日誌磁碟使用量是否持續增加

TransactionLogsDiskUsage 的 CloudWatch 指標代表交易 WAL 使用的磁碟空間。交易日誌磁碟使用量可能會增加,原因是:

  • 高資料庫負載 (產生額外的 WAL 的寫入和更新)
  • 串流會讀取複本延遲 (相同區域中的複本) 或讀取處於儲存體已滿狀態的複本
  • 複寫插槽

複寫插槽可以建立為 AWS Database Migration Service (AWS DMS) 邏輯解碼功能的一部分。對於邏輯複製,插槽參數 rds.logical_replication 會設為 1。複寫插槽會保留 WAL 檔案,直到檔案遭取用者從外部消耗為止。例如,它們可能會由 pg\ _recvlogical、擷取、轉換和載入 (ETL) 任務或 AWS DMS 使用。

如果您將 rds.logical_replication 參數值設為 1,則 AWS RDS 會設定wal_levelmax_wal_sendersmax_replication_slotsmax_connections 參數。變更這些參數可能會增加 WAL 的產生。最佳實務為僅在使用邏輯插槽時才設定 rds.logical_replication 參數。如果此參數設為 1,且存在邏輯複寫插槽,但複寫插槽所保留的 WAL 檔案沒有取用者,則交易日誌磁碟使用量可能會增加。這還會導致可用儲存空間不斷減少。

執行此查詢以確認複寫插槽的存在和大小:

PostgreSQL 第 9 版:

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 第 10 版及更高版本:

psql=> SELECT slot_name, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(),restart_lsn)) AS replicationSlotLag,
active FROM pg_replication_slots ;

識別未使用的複寫插槽 (使用中狀態為 False) 之後,執行下列查詢來捨棄複寫插槽:

psql=> SELECT pg_drop_replication_slot('Your_slotname_name');

注意事項: 如果 AWS DMS 任務是取用者且不再需要它,則刪除該任務並手動捨棄複寫插槽。

範例輸出:

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

在此範例中,插槽名稱 xc36ujql35djp_00013322_907c1e0a_9f8b_4c13_89ea_ef0ea1cf143d 的作用中狀態為 False。因此,不會主動使用此插槽,並且插槽會提供 129 GB 的交易檔案。

執行下列命令來捨棄查詢:

psql=> SELECT pg_drop_replication_slot('xc36ujql35djp_00013322_907c1e0a_9f8b_4c13_89ea_ef0ea1cf143d');

檢查跨區域讀取複本的狀態

使用跨區域讀取複寫時,即會在主要執行個體上建立實體複寫插槽。如果跨區域讀取複本失敗,則可能會影響主要資料庫執行個體上的儲存空間。發生這種情況是因為 WAL 檔案不會複寫到讀取複本。您可以使用 CloudWatch 指標、最舊的複寫插槽延遲和交易日誌磁碟使用量來判斷延遲最多的複本有多落後。您還可以查看 WAL 資料使用了多少儲存體。

若要檢查跨區域讀取複本的狀態,請使用 query pg_replication_slots。如需詳細資訊,請參閱 pg_replication_slots 的 PostgreSQL 文件。如果使用中狀態傳回為 false,則該插槽目前不會用於複寫。

psql=> SELECT * FROM pg_replication_slots;

您也可以在來源執行個體上使用 pg_stat_replication 以檢查複寫的統計資料。如需詳細資訊,請參閱 pg_stat_replication 的 PostgreSQL 文件。

檢查膨脹或不當去除無效資料列 (元組)

在正常的 PostgreSQL 作業中,不會從其表格中刪除由 UPDATE 刪除或過時的元組。對於 Multi-Version Concurrency Control (MVCC),當執行 DELETE 作業時,資料列不會立即從資料檔案中移除。相反地,透過在標題中設定 xmax 欄位,將該資料列標記為已刪除。更新首先標記要刪除的資料列,然後執行插入作業。這允許在不同的交易之間以最小鎖定並行。因此,不同的資料列版本會當作 MVCC 程序的一部分予以保留。

如果沒有清理無效資料列,它們可以保留在資料檔案中,但保持不對交易顯示,這會影響磁碟空間。如果表格有許多 DELETEUPDATE 作業,則無效元組可能會使用大量磁碟空間,有時在 PostgreSQL 中稱為「膨脹」。

VACUUM 作業可以釋放無效元組使用的儲存體,以便重複使用,但不會將可用儲存體釋放到檔案系統中。執行 VACUUM FULL 將儲存體釋放到檔案系統中。但是請注意,在 VACUUM FULL 執行期間,表格上會保留存取專屬鎖定。此方法也需要額外的磁碟空間,因為會寫入表格的新副本,而且在作業完成之前不會釋放舊副本。最佳實務為當您必須從表格內回收大量空間時,才會使用此方法。最佳實務亦為在經常更新的表格上執行定期 VACUUM 或 AUTOVACUUM 作業。如需詳細資訊,請參閱 VACUUM 的 PostgreSQL 文件。

若要檢查預估的無效元組數量,請使用 pg_stat_all_tables 視圖。如需詳細資訊,請參閱 pg_stat_all_tables 視圖的 PostgreSQL 文件。在這個範例中,有 1999952 個無效元組 (n_dead_tup):

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     | 2018-08-16 04:49:52.399546+00
last_analyze        | 2018-08-09 09:44:56.208889+00
last_autoanalyze    | 2018-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.    執行這些查詢以評估已使用和實際大小。

# Size of the database occupied by files
psql=> SELECT pg_size_pretty(pg_database_size('DATABASE_NAME'));

# Size of database retrieved by summing the objects (real size)
psql=> SELECT pg_size_pretty(SUM(pg_relation_size(oid))) FROM pg_class;

3.    記下結果。如果差異很大,則孤立檔案可能正在使用儲存空間。


相關資訊

使用適用於 Amazon RDS for PostgreSQL 的讀取複本

自動化監控工具