Amazon RDS for PostgreSQL で発生する「デバイスに空き領域がありません」または「DiskFull」エラーの原因を特定するには、どうすれば良いですか?

最終更新日: 2019 年 4 月 16 日

私は PostgreSQL データベース用の小規模 Amazon Relational Database Service (Amazon RDS) を持っています。インスタンスストレージの空き容量が減少していて、次のエラーが表示されました。

"Error message: PG::DiskFull: ERROR: could not extend file "base/16394/5139755": No space left on device.HINT: Check free disk space."

DiskFull エラーを解決するにはどうすれば良いですか? また、ストレージ容量不足の問題を回避するにはどうすれば良いですか?

簡単な説明

Amazon RDS DB インスタンスストレージは、以下によって使用されます。

  • PostgreSQL トランザクションによって作成された一時テーブル
  • データファイル
  • 先書きログ (WAL ログ)
  • 消費されていないレプリケーションスロット
  • 長期間保存されている DB ログ (エラーファイル)
  • 停止しているクロスリージョンリードレプリケーション
  • RDS DB インスタンスの一貫した状態をサポートする他の DB ファイルまたは Linux ファイル

解決方法

Amazon CloudWatch を使用して、FreeStorageSpace メトリクスを使って DB ストレージ容量をモニタリングします。ストレージの空き容量に対して Amazon CloudWatch アラームを設定すると、容量が減少し始めるときに通知を受け取ります。アラームを受信した場合は、ストレージ問題で以前に考えた原因を確認できます。また、log_temp_files のログをモニタリングして、いつどのように一時ファイルが作成されるのかを確認することをお勧めします。それでも DB インスタンスが予想より多くのストレージを消費している場合は、以下を確認してください。

  • DB ログファイルのサイズ
  • 一時ファイルの有無
  • トランザクションログのディスク使用量が常に増加しているか
  • クロスリージョンリードレプリカ
  • 実行されない行の肥大化または不適切な削除
  • 孤立したファイルの有無

DB ログファイルのサイズを確認する

デフォルトでは、PostgreSQL エラーログファイルの保持期間は 4,320 分 (3 日) です。大きなログファイルはより大きいサイズを使用することがあり、これはより高いワークロードにつながる可能性があります。DB インスタンスに関連付けられている DB パラメータグループの rds.log_retention_period パラメータを使用して、システムログの保持期間を変更できます。たとえば、値を 1440 に設定した場合、ログは 1 日間保持されます。詳細については、「PostgreSQL データベースのログファイル」を参照してください。

一時ファイルを確認する

一時ファイルはバックエンドまたはセッション接続ごとに保存されるファイルであり、リソースプールまたはバッファとして使用されます。これらのファイルは、共有リソーススペースとは別に保存されます。これらのファイルを確認するには、次に示すようなコマンドを続けて実行した差分を使用します。

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) など、サーバー起動時の復旧によってのみリセットされるように設計されているためです。このため、出力のみを確認するのではなく、これらのファイルの数とサイズの増加をモニタリングすることをお勧めします。

一時ファイルは、並べ替え、ハッシュ、および一時的なクエリ結果用に作成されます。ファイルが削除されると、各一時ファイルのログエントリが作成されます。単一クエリで使用される一時スペースの作成を追跡するには、カスタムパラメータグループに log_temp_files を設定してください。このパラメータは、一時ファイルの名前とサイズのログ記録をコントロールします。log_temp_files 値を 0 に設定すると、すべての一時ファイル情報がログに記録されます。このパラメータを正の値に設定した場合、指定されたキロバイト数以上のファイルサイズのみがログに記録されます。デフォルト設定は -1 です。この場合、一時ファイルの作成と実行されたステートメントがログに記録されます。また、クエリの EXPLAIN ANALYZE を使用してディスクの並べ替えを確認することもできます。ログ出力を確認すると、クエリによって作成された一時ファイルのサイズを確認できます。詳細については、データベースのアクティビティをモニタリングするための PostgreSQL ドキュメントを参照してください。

トランザクションログのディスク使用量が常に増加しているか確認する

TransactionLogsDiskUsage の CloudWatch メトリクスは、トランザクション WAL によって使用されるディスク容量を表します。次のことが原因で、トランザクションログのディスク使用量が増加する可能性があります。

  • 高い DB 負荷 (追加の WAL を生成する書き込みおよび更新)
  • リードレプリカがストレージフル状態 (プライマリインスタンスのトランザクションログを保持)。
  • レプリケーションスロット

レプリケーションスロットは、AWS Database Migration Service (AWS DMS) の論理デコード機能の一部として作成できます。論理レプリケーションの場合、スロットパラメータ rds.logical_replication1 に設定されています。レプリケーションスロットは、pg_recvlogical、抽出、変換、ロード (ETL) ジョブ、または AWS DMS など、コンシューマーによってファイルが外部的に使用されるまで WAL ファイルを保持します。

rds.logical_replication パラメータの値を 1 に設定した場合、AWS DMS は wal_levelmax_wal_sendersmax_replication_slots、および max_connections のパラメータを設定します。これらのパラメータを変更すると WAL 生成が増加する可能性があるため、論理スロットを使用している場合にのみ rds.logical_replication パラメータを設定することをお勧めします。このパラメータが 1 に設定されていて、論理レプリケーションスロットが存在し、レプリケーションスロットによって保持されている 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 および v11

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
----------------------------------------------------------------+--------------------+--------
xc36ufspjql35djp_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

この例で、スロット名 xc36ufspjql35djp_00013322_907c1e0a_9f8b_4c13_89ea_ef0ea1cf143d のアクティブ状態は False です。そのため、このスロットはアクティブに使用されておらず、スロットは 129 GB のトランザクションファイルに使用されています。

次のようなコマンドを実行してクエリを削除できます。

psql=> select pg_drop_replication_slot('xc36ufspjql35djp_00013322_907c1e0a_9f8b_4c13_89ea_ef0ea1cf143d');

クロスリージョンリードレプリカ

クロスリージョンリードレプリケーションを使用する場合、プライマリインスタンスに物理レプリケーションスロットが作成されます。クロスリージョンリードレプリカが失敗すると、WAL ファイルがリードレプリカにレプリケートされないため、プライマリ DB インスタンスのストレージ容量に影響が及ぶ可能性があります。CloudWatch メトリクス、最も古いレプリケーションスロットの遅延、およびトランザクションログのディスク使用量を使用すると、受信した WAL データと WAL データに使用されているストレージの量に関して、最も遅延しているレプリカよりどれだけ遅れているかを判断できます。

クロスリージョンリードレプリカのステータスを確認するには、pg_replication_slots をクエリしてください。詳細については、pg_replication_slots クエリに関する PostgreSQL のドキュメントを参照してください。アクティブ状態が false として返された場合、そのスロットは現在レプリケーションに使用されていません。

postgres=# select * from pg_replication_slots;

レプリカ遅延 CloudWatch メトリクスおよびイベントに加えて、ソースインスタンスでビュー pg_stat_replication を使用して、レプリケーションの統計を確認できます。詳細については、pg_stat_replication に関する PostgreSQL のドキュメントを参照してください。

実行されない行 (タプル) の肥大化または不適切な削除

通常の PostgreSQL 操作では、UPDATE によって削除されたか、時代遅れになったタプルは、それらのテーブルから削除されません。多版型同時実行制御 (MVCC) 実装では、DELETE 操作が実行されても、行はデータファイルからすぐには削除されません。代わりに、ヘッダーの xmax フィールドを設定することによって、行が削除済みとしてマークされます。更新でも同様に、最初に行を削除対象としてマークし、次に挿入操作を実行します。これにより、異なるトランザクション間でロックを最小限に抑えながら、同時実行が可能になります。その結果、異なる行バージョンが MVCC プロセスの一部として保持されます。

実行されない行がクリーンアップされないと、それらはデータファイルに残り (トランザクションからは表示されない)、ディスク容量に影響を与える可能性があります。テーブルに多くの DELETE および UPDATE 操作がある場合、実行されないタプルは大量のディスク容量を使用する可能性があります。これは PostgreSQL では肥大化と呼ばれることがあります。

VACUUM 操作は、実行されないタプルによって占有されているストレージを解放することができます。頻繁に更新されるテーブルに対して、定期的なバキューム操作または自動バキューム操作を実行することをお勧めします。詳細については、VACUUM に関する PostgreSQL のドキュメントを参照してください。

実行されないタプルの推定数を確認するには、pg_stat_all_tables ビューを使用してください。詳細については、pg_stat_all_tables ビューに関する PostgreSQL のドキュメントを参照してください。次の例には、実行されないタプル (n_dead_tup) が 1999952 個あります。

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 FULL、または CLUSTER などの操作中にインスタンスがストレージ不足になった場合に発生する可能性があります。孤立したファイルを確認するには、次の手順に従ってください。

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.    結果をメモしてください。この違いは重要です。

ファイルによって占有されているデータベースのサイズと、オブジェクトを合計して取得されたデータベースのサイズとの間に大きな違いがある場合、孤立したファイルがストレージ容量を使用している可能性があります。


この記事は役に立ちましたか?

改善できることはありますか?


さらにサポートが必要な場合