RDS for Postgresqlのトランザクションログとリードレプリカの関係を理解する

2019.08.11

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

瀬田@大阪オフィスです。

俺が知りたいから調べるシリーズです。RDSに慣れてからというもの、WAL設計を気にしなくなりつつあったのですが、リードレプリカの挙動と切っても切り離せないので勉強がてら調べてみました。これもトラウマが(略

マルチAZのスタンバイとリードレプリカの違い

違いは以下となります。今回はリードレプリカの話題です。

マルチAZのスタンバイ

  • ストレージレベルの同期レプリケーション
  • AZ間をまたぐ
  • WALログは関係ない

リードレプリカ

  • DBエンジンの機能を利用したいわゆる普通のレプリケーション
  • 非同期レプリケーション
  • AZは任意で選択可能
  • WALログが生成される
  • リージョン間のリードレプリカはレプリケーションスロットが作成される
  • 同一リージョン間はレプリケーションスロットを使用しない

リードレプリカのトランザクションログ

リードレプリカはDBエンジンの機能を使うのでエンジンに依存した挙動をします。つまりオンプレの時と注意点はそんなに変わらないということです。

よくあるパターン1

現象

同一リージョンのリードレプリカで発生する問題です。 WALの保有数上限を決める「wal_keep_segments」パラメータが設定されますが、大量の更新が発生した場合、この上限をこえてWALが生成されます。この場合以下の挙動となります。

  • WAL生成数がwal_keep_segmentsの数を越えた場合、最も古いWALに上書きされる。
  • 上記のWALがリードレプリカに転送前であった場合、データの不整合が起きてリードレプリカでレプリケーションのリカバリが走る。
  • リードレプリカはS3からWALを取得し、ロストしたトランザクションを補填し、レプリカを再開する。
  • この時間がレプリケーションの遅延として検知される。

この現象が発生した場合は、レプリカ側のログに以下のようなログが記録されます。 FATAL: could not receive data from WAL stream: ERROR: requested WAL segment 0000000000000000B00000000 has already been removed

マスタ側のログではcheckpoint completeのログを確認することで、removedされたWALの数を確認できます。 checkpoint complete: wrote 185554 buffers (2.2%); 0 transaction log file(s) added, 28 removed, 35 recycled; write=7.000 s, sync=0.060 s, total=9.000 s; sync files=83, longest=0.011 s, average=0.000 s; distance=323232 kB,

対応

wal_keep_segmentsの数をマスタ側で増やします。wal_keep_segments数*16MBのストレージをマスタ側で使用するため、ストレージ空き容量に余裕があるか確認してください。wal_keep_segmentsは無停止で変更が可能です。

よくあるパターン2

現象

別リージョンへのリードレプリカ で発生する問題です。 レプリケーションスロットの機構により、リードレプリカに転送されないWALファイルはwal_keep_segmentsの数を越えてもマスタ機に滞留するようになります。このときに発生する現象は以下です。

  • リードレプリカが停止する。
  • マスタ側でWAL転送が行えないため、リードレプリカ復旧までWALが上限なく滞留する。
  • 滞留したWALがストレージを圧迫し、マスタ機が停止する。

対応

リードレプリカが停止から復旧する許容時間を定義し、その間に溜まるWAL数を算出し、必要ストレージをマスタ側に確保します。または、マスタ側のストレージ容量の監視を実施し、逼迫前に検知してリードレプリカ を復旧または切り離しを行います。

最後に

リージョン越えのレプリケーションを利用している場合は少し注意したいですね。