tom__bo’s Blog

MySQL!! MySQL!! @tom__bo

PostgreSQL WALとPITR

前回の内容からレプリケーション構成を組んでみようと意気込んでいましたが、そのためにWAL(Write Ahead Logging)やアーカイブログ、PITR(Point in Time Recovery)の知識があったほうが理解が出来そうなので、こちらをまとめることにしました。

引き続きwww.amazon.co.jp
を読んでいきます。2-9, 2-10章のまとめ記事にしようと思いましたが、このエントリは自分用のメモにしかなリませんでした( ´ー`)


WAL

  • 共有バッファ(メモリ)のデータをデータ領域(HDD)に書き込む前にプロセスがクラッシュした際にデータを失わないための仕組み。
  • データの変更情報をWALログという16MBのファイルにシーケンシャルに書き込んでいる。
  • 後にWALを利用して、PITRやレプリケーションに使われるようになった。
WALへのログ書き込みとリカバリ手順
  • WALログにはLSN(Log Sequence Number)という番地が定義されている。
  • CHECKPOINT開始直後の位置をREDOポイントといい、リカバリの起点にする
  • ブロック1にタプルを追加する。CHECKPOINT以降初めての更新なので、ブロック全体をWALログに書き込む。ヘッダ情報としてLSN_1を書き込む。これをバックアップブロックと言う。
  • ブロック1への今後の変更は差分のみをWALに書き込み、LSN_2, 3,,,と続ける。他のブロックでも同様にする。
  • リカバリ時はブロックごとのバックアップログでブロックを上書きしバックアップログより大きい番地の差分を適用することで、更新を完了させる。
WALログの構造
  • WALの情報は以下の3つの情報で管理されている。
データ名 説明 バイト長
tli TimeLineID 4
xlogid ログID 4
xrecoff ログID毎のオフセット 4
  • xlogidとxreoffの組をLSNと呼ぶ。
  • WALログは理論上xlogidごとに4GBを確保している(?)が、実際は16MBのセグメント毎にファイル化している。
  • WALログファイルの命名規則
    • ファイル名 = TimeLineID + xlogid + (00000000から000000FEまでの連番)
    • これによりWALログのアドレス指定、LSNからLSNを含むセグメントを知ることができる。
WALログに書き込むデータ

(図による理解が大部分なので、かなり省略)

  • 16MBのWALログの内部は8MBのページに分割されている。
    • ページの先頭部分:XLogLongPageHeaderData
    • ページ内部:XLogRecord
    • 残りの部分:データ部
WALログの書き込みシーケンス
  1. UPDATE文を実行(ユーザによる実行で複数行を変更するもの)
  2. CLOGの更新(XIDの状態を"IN_PROGRESS"に設定する
  3. 更新データをWALバッファに書き込む
  4. 他のレコードも同様に処理する
  5. COMMITに関するWALログをWALバッファに書き込む
  6. (COMMIT後) WALログに同期書き込みする
  7. CLOGの更新(XIDの状態を"COMMITTED"にする)

以上がCOMMIT時のWALログ書き込みの手順だが、他にもWALログの書き込みタイミングが有る。

    • 実行中のトランザクションのどれかがCOMMITされた時
    • WALバッファがあふれた時
    • CHECKPOINT, VACUUM実行時
    • WALライタが作動した時(後述)

COMMITのレスポンスを返す直前にプロセスがクラッシュした場合を考える。
WALの書き込みに注目すると、

    • WALの同期書き込み時(書き込み前)にクラッシュ
    • WALの同期書き込み後にクラッシュ

が考えられる。しかし、ドリラのパターンでもリカバリ後のDBの一貫性、永続性が保たれていることがわかる。
しかし、このトランザクションがABORTしたのか、COMMITしたが、レスポンスを返せなかったかは不定のため、ユーザが確認する必要がある。COMMITしていたにもかかわらずREDO処理を複数回するとこの操作は冪等でないので、データの一貫性を損ねてしまうことになる。



WALログ書き込みに関する機能
  • 設定パラメータcommit_delayを設定することでその時間だけCOMMITを待ち、複数トランザクションのCOMMITを同時に行う遅延コミット(COMMIT Delay)がある。
  • これにより、トランザクションごとのレスポンス時間は長くなるが、全体のスループットを向上できる可能性がある。

アーカイブログとPITR

  • PITRはある時点でのデータベースクラスタとそれ以降のアーカイブログを使って、別サーバ上でデータベースを再構築する機能。
  • アーカイブログは物理的にはWALログそのものでこれはデータベースクラスタのpg_xlogディレクトリに予めいくつか用意された16MBのファイル。
    • 1つのWALの全領域にデータを書き込むと、次のWALに書き込み先を変える。
    • wal_keep_segmentsで設定された数はアーカイブとして残すが、これを超えた分はrenameして再利用する。


WALログの切り替えのタイミングは以下。

  • WALログを使いきった時
  • 関数pg_switch_xlog()を実行した時
  • アーカイブログモード (archive_mode=on)で設定パラメータarchive_timeoutに設定した時間が過ぎた時
ベースバックアップ

データベースクラスタのスナップショットを「ベースバックアップ」という。
PostgreSQLではベースバックアップのコピー中でも、データベースの検索や更新が可能

ベースバックアップを取る手順は以下。

  1. 関数pg_start_backup()を実行
    • WALログ切り替え
    • CHECKPOINT実行
    • backup_label生成
  2. データベースクラスタ領域を他のサーバやストレージにコピー
    • データ領域をscp等でコピー
  3. 関数pg_stop_backup()を実行
    • バックアップ終了のWALログを書き込む
    • WALログ切り替え
    • バックアップヒストリーファイルを作成


WAL, アーカイブログ、PITRの概要がだいぶ理解できたつもりだが、このエントリ自体はただの箇条書きになってしまった。
参考の本だと約30ページぐらいの内容で、各ページに必ずと言っていいくらい図によって説明があるので、本を読むのが一番良さそうだ。。。


終わり ⊂゚U┬───┬~