RDS Postgresqlのディスク使用量を削減する(pg_repack)

2019.05.27

はじめに

瀬田@大阪オフィスです。 Postgresqlのディスクがぱっつんぱっつんになった悪夢を思い出しました。RDSでも使えるpg_repackをご紹介します。

お題

Postgresqlは追記型DBのため、Deleteしてもディスク容量はOS側に解放されないのは周知の事実です。VACUUM FULLがかけれればいいのですが、運用系で停止はできない状況は多々発生します。そんな時の救世主「pg_repack」をご紹介します。

pg_repackとは

本家の説明は以下となっております。 pg_repack

pg_repack はPostgreSQLの拡張の一つで、肥大化したテーブルやインデックスを再編成し、さらに指定したインデックスにしたがってレコードを並び替えることができます。 PostgreSQLの CLUSTER や VACUUM FULL コマンドと違って、pg_repackは処理の間対象テーブルへの排他ロックを保持し続けないため、オンライン中に動作させることができます。 pg_repackはCLUSTERコマンドを直接実行するのと同じくらいの性能で起動することができて効率的です。

肥大化したテーブルに対して、再編成処理を(ほぼ)オンラインにて実施することが可能です。動作内容は公式ドキュメントから以下です。

  1. 対象のテーブルに対して実行される変更を記録するためのログテーブルを作成します
  2. 対象のテーブルに、INSERT、UPDATE、DELETEが行われた際にログテーブルに変更内容を記録するトリガを追加します
  3. 対象テーブルに含まれるレコードを元に、新しいテーブルを指定した編成順でレコードを並ばせながら作成します
  4. 新しいテーブルに対してインデックスを作成します
  5. 再編成中に行われた元のテーブルに対する変更内容をログテーブルから取り出し、新しいテーブルに反映します
  6. システムカタログを更新し、元のテーブルと新しいテーブルを入れ替えます。インデックスやトーストテーブルも入れ替えます
  7. 元のテーブルを削除します

pg_repackは上の手順の中で、始めの1.と2.の時点、および最後の6.と7.の時点で対象のテーブルに対する ACCESS EXCLUSIVEロックを取得します。その他のステップでは、ACCESS SHAREロックを必要とするだけなので、 元のテーブルに対するINSERT, UPDATE, DELETE操作は通常通りに実行されます。

ごく短時間のロックが取得されるだけのため、DDLが頻発しているような特殊な環境でなければ本番稼働にほぼ影響なく実施できます。

注意点

  1. 本番データに対して処理がかかります。本番環境のコピー等で必ず事前検証、バックアップを実施してください。
  2. テーブル全体の再編成を行うには、対象となるテーブルと付属するインデックスのおよそ2倍のサイズのディスク空き容量が必要です。
  3. 短時間とはいえロックを取得され、負荷もあるため夜間等の影響の少ない時間帯での実行をお勧めします。
  4. 動作中はDDLを実行しないでください。

    大抵はpg_repackが失敗してロールバックが適切に行われますが、古いバージョンでは いくつかのケースでデータ不整合を引き起こす可能性があります。

実行手順

RDSにはすでにインストールされているため、EXTENSIONを設定することで実行可能です。実行手順については以下の公式ドキュメントご確認ください。
pg_repack 拡張機能の使用

トラブルシューティング

運用系のテーブルを触るため、発生するエラーや失敗時の動作については事前に把握しておきたいです。対処法は公式ページによくまとまっています。
pg_repack トラブルシューティング

最後に

自分がよく救われたpg_repackをご紹介しました。自由にキャパシティをあげるAWSとはいえ、色々な選択肢は持っておきたいですね。