PostgreSQL version 9.5 のWALファイル管理

このブログに限り完全に著作権を放棄します(あくまでこのブログだけ。他のブログ、および下の英語文書は範囲外)。勝手に使ってよし。2016.12.20
公開した文書のごく一部を、翻訳して公開。(BLOGにするにあたり、構成は変えた。)

http://www.interdb.jp/pg

概要

  1. checkpoint_segmentsが廃止され、WALファイル数の上限下限をmax_wal_sizeとmin_wal_sizeで指定できるようになった。
  2. WALファイル数は(これらの制限内で)サーバの活動状況=WALファイルの消費量に合わせて変化する。あまり書き込みがなければWAL数は減少し、活発になればWAL数が増える。
  3. 保存するWAL数は基本的にリカバリに必要不可欠なものに限られ、無駄なWALファイルを溜め込む事は無くなった。

理解のための前提条件

CHECKPOINTの起動タイミング

CHECKPOINTは以下のどれか一つが発生した場合に起動する。

  1. checkpoint_timeoutに設定した時間が、前回のcheckpointから経過した場合。デフォルトのインターバルは300秒(5分)。
  2. バージョン9.4以前では、checkpoint_segmentsに設定した数のWALセグメントファイルが、前回のcheckpointから消費された場合。デフォルトの数は3。
  3. バージョン9.5の場合、pg_xlog以下のWALファイルの総サイズがmax_wal_sizeを超えた場合。デフォルトのサイズは1Gbyte (64ファイル)。
  4. smart かfastモードでPostgreSQLサーバが停止する場合
  5. 手動でCHECKPOINTコマンドを実行した場合
  6. pg_start_backup()関数が実行されたとき

version 9.5からはcheckpoint_segments(廃止)でなく、max_wal_sizeによることに注目。

リカバリの概要

リカバリはCHECKPOINT起動直後のWALデータ書き込み位置=REDOポイントから始まる。もしもlast REDOポイントが読めない場合は、前の(prior) REDOポイントから始める。どちらも読めなければリカバリを諦める。

ここで大事な点は、リカバリ機構から明らかなように、「prior REDOポイントを含むWALファイルよりも古いファイルは不要」ということ。


注:「checkpointが終ったらprior-last間のWALファイルも消せば?」的意見もありますが(checkpointが終ったらというのも微妙だが)万が一 last-checkpoint recordが読み取り不可だった場合であってもprior checkpoint recordからリカバリできるので、決してprior-last間のWALファイルが無駄に保存されているわけではないので、誤解無きよう...

version 9.4までのpg_xlog以下のWALファイルの管理方法

WALセグメントファイルの数は主に以下の3つのパラメータで制御される:

  • checkpoint_segments
  • checkpoint_completion_target
  • wal_keep_segments

WALファイルの数は通常は (2 + checkpoint_completion_target) * checkpoint_segments + 1checkpoint_segments + wal_keep_segments + 1 files のどちらか大きいほうになる。この数はサーバのactivityによっては一時的に 3 * checkpoint_segments + 1 files まで拡大するときがある。

上に書いたように、CHECKPOINTはcheckpoint_segments個のWALファイルを消費したときに起きる。WALファイルの数は常に2*checkpoint_segmentsよりも大きいから、2つ以上のREDOポイント(lastとpriorは確実に、それ以前のものも)が常にWALファイルの中に含まれていることが保証されている。CHECKPOINTがタイムアウトによって発生しても同様である。よって、version 9.4以前のPostgreSQLリカバリのために十分な(時として必要以上の)WALファイルを常にpg_xlog以下に保存している。
実際のところ、checkpoint_segmentsは頭痛の種である。小さな値を設定すると頻繁にCHECKPOINTが発生して性能低下を引き起こし、大きな値を設定すると巨大なディスク領域が常に必要となるにも関わらず(保存された)WALファイルのすべてが必要とは限らない、というトレードオフ問題を抱え込んでしまう。

version 9.5のWALファイルの管理方法

Version 9.5でpg_xlog以下のWALファイルの管理方法が大幅に改善された。
CHECKPOINTが起動する度にPostgreSQL次のcheckpointサイクルでいくつのWALファイルが必要か推定し、推定された数のファイルをpg_xlog以下に用意する。推定値は以前のcheckpointサイクルで消費されたファイル数から計算する。計算式は突発的な変化にはあまり影響されず、大まかな傾向が反映されるようなものを使っている*1。また、推定値はprior REDOポイントを含むファイルから数え、その数はmin_wal_size (デフォルト 80Mbyte, 5 files)とmax_wal_size(1 Gbyte, 64 files)の間の値である*2

CHEKPOINTが起動する際、必要な数のファイルは保持もしくはリサイクルし、不要なファイルは削除する。具体的な例を下図に示す。CHECKPOINTの実行直前には6つのファイルがあり、そのうちWAL_3がprior REDOポイントを含む、そしてPostgreSQLは5つのファイルが必要と推定したと仮定する。この場合、WAL_1をWAL_7にリサイクルし、WAL_2は削除する。

もしもWALの活動が突発的に上昇してもっとWALファイルが必要になった場合、総サイズがmax_wal_size未満の間は新しいファイルを作成する。例えば、下図において、WAL_7が一杯になったら、WAL_8を新たに作成する。

このように、書込みが減れば推定値も小さくWALファイル数も減る;書込みが増えればそれに合せて推定値も大きくなり、WALファイル数も増える。いずれにせよ書込みが定常的に続くならWALファイル数もそれに応じた数に落ち着く(平衡する)。


激しい書込みがずっと続くと(checkpointの度に)推定値が徐々に増えていくが、それでも間に合わずにWALファイルが追加され、結果的に総サイズがmax_wal_sizeを超えたら、(新たに)CHECKPOINTが起動する。下図にこの状況を示す。CHECKPOINTによってあたらしいREDOポイントが生成され、last REDO pointはprior REDOポイントになる。そして不要な古いファイルはリサイクルする。

このように、version 9.5は常にデータベースリカバリに必要なWALセグメントファイルだけを保持するので、上に述べたトレードオフ問題も解消できる。

*1:En+1を次回の推定値、Cnを今回の消費量、Cn-1を前回の消費量とすると、En+1 = 0.1*Cn + 0.9*Cn-1。 直近の消費量Cnに重み0.1を、その前の消費量に重み0.9を乗算するすることで、一時的に急激な変動があっても大きく影響を受けないような推定値計算法を採用している。

*2:version 9.4までもCHECKPOINT起動時に用意していたが、prior REDOポイントの位置は考慮していなかったし、このような賢い推定もしていなかった。