[InterDB] [著者HP] [PREVIOUS][UP][NEXT]

Copyright @ 2009, Suzuki Hironobu @ InterDB


■2-09■ WALとは(Write Ahead Logging)


日本PostgreSQLユーザ会仕組み分科会で発表したWALとPITRの資料pgpool-IIのオンラインリカバリに関する資料がありますので、こちらも参照してください。



WALはトランザクションロギングを行うための一手法です。WALが実装されたことにより、ハードディスクのアクセス回数が減ったため、データベースシステムのパフォーマンスが向上しました。また、サーバやOSが突然クラッシュしても、データの一貫性を損なわずにデータベースシステムを復旧できるようになりました(補足 1)。
WALはPostgreSQLのパフォーマンスと信頼性を確保するための重要な機構ですが、その理解にはUnix系OSの基礎知識が必要です。ここでは、OSのデータ書き込みから順を追ってWALの仕組みを解説していきます。

OSのデータ書き込み

Unix系OSはハードディスクにデータを書き込む際、一旦カーネルのバッファキャッシュに保存し、後に適当なタイミングでハードディスクに書き込みます。アプリケーション側の書き込みとハードディスクへの書き込みが非同期に行われるので、これを非同期書き込みといいます。
なぜ二段階に分けるかといえば、ハードディスクの動作が遅いからです。複数のデータをバッファキャッシュに溜めて、後で一挙にデータ書き込みをしたほうがOS全体のパフォーマンスが向上します(【図.2-12】参照)。

図.2-12 一般的なOSのデータ書き込み(非同期)


ただし、バッファキャッシュに保存した直後にトラブルが起こると、当然ながらデータはハードディスクに記録されることなく消失してしまいます。これはすべてのアプリケーション(特にデータベースシステム)にとって致命的な問題です。
このような事態を避ける方法として、同期書き込み(常にバッファキャッシュとハードディスクの内容を一致させる)があり、次の2つの方式があります(【図.2-13】参照)。


(1)バッファキャッシュへ書き込んだ直後にfsync()システムコールを呼び出し、強制的にハードディスクに書き込む(補足 2) 
(2)同期モードでopen()システムコールを呼び出し、データを逐次、ハードディスクに書き込む


図.2-13 同期書き込み


以降、同期書き込みは実線、非同期書き込みは破線で表示し、カーネルのバッファキャッシュは図示しません。



バージョン7.0までのデータ書き込み:WAL以前

バージョン7.0 まではWAL が実装されておらず、ハードディスクへのデータ書き込みは、非同期書き込みか同期書き込み(デフォルト)のいずれかを選択しなければなりませんでした。
非同期書き込みの場合、テーブルのデータを更新してもすぐにはハードディスクに書き込まれません。ディクスアクセス回数が減るのでパフォーマンスは向上しますが、停電などの障害によりOSやデータベースプロセスがクラッシュした場合、データの一貫性が損なわれて甚大な被害が出る可能性があります。
一方、同期書き込みはデータの更新ごとにハードディスクに書き込みますので、データの一貫性は保たれますが、ハードディスクアクセスが頻発するためパフォーマンスが大幅に低下します。
つまり、WAL導入以前は、非同期書き込みで安全性を犠牲にするか、同期書き込みでパフォーマンスを犠牲にするかを選択しなければなりませんでした(【図.2-14】参照)。

図.2-14 非同期書き込みと同期書き込み



WALの基本動作

バージョン7.1からWALが実装されました。ここでデータの検索、および更新がどのように行われるのか、各バッファとハードディスクとのデータのやりとりに焦点を合わせて説明します。
なお、WALの基本的動作を把握するため細部の説明を省き、概略のみ説明します。WALの詳細は【2-10】でまとめて解説します。


    (a)検索(【図.2-15】参照)
    共有バッファにキャッシュされたデータを検索します。目的のデータが存在すればそのデータを利用し、存在しない場合はハードディスクからデータを読み出します。

    図.2-15 SELECT
    
    

    (b)更新(補足 3)(【図.2-16】参照)
    
    (1)トランザクションログをWALバッファに書き込み、共有バッファ内のデータを変更します。
    十分に大きな共有バッファが確保されているなら、テーブルに対する操作(更新、削除、挿入)は
    すべて共有バッファ上のデータに対して行われ、(3)のCHECKPOINT が実行されるまで
    ハードディスクには反映されません。
    
    (2)WALバッファが溢れるか、トランザクションがコミットされた時点で、WALバッファの内容を
    WALログ(補足 4)に書き込みます。
    WALログにはシーケンシャルに同期書き込みを行います
    (ログの末尾に追加していく。よって同期書き込みといえども、高速に書き込みできる)。
    
    (3)CHECKPOINTが実行されると、共有バッファ内のデータをハードディスクのデータ領域に書き出し、
    WALログを新規作成します(データの更新がハードディスクに反映されたので、
    今まで使っていたWALログが不要になったため)。
    なお、チェックポイントの実行は、実行時パラメータ“checkpoint_timeout”で設定された
    秒数間隔毎(デフォルト3 0 0 秒)か、WAL ログを使い切った時にPostgreSQLサーバによって
    自動的に行われます。
    

    図.2-16 UPDATE
    
    


データ操作は共有バッファをキャッシュとして利用しているので、高速にデータ処理ができます。また、トランザクションログを同期書き込みで保存しているので、トラブルがあってもWALログを使ってデータベースを復旧することができます。

復旧

事故後の復旧について解説します。いくつかのSQL文が実行された直後、システムがクラッシュしたとします。ここでPostgreSQLを再起動すると、復旧処理がはじまります。
ハードディスクには、最後のCHECKPOINT時点でのデータが保存されており、それ以降の変更はWALログにだけ保存されています。そこで、WALログに記録されたSQL文を順に再実行(Redo)することで、クラッシュ直前の状態にまで復旧することができます(【図.2-17】参照)。


「WALの詳細」へ進む →

図.2-17 復旧処理


補足


(1)
ハードウエア障害など、深刻なトラブルの場合は復旧できません。

(2)
正確には、fsync()システムコールは“カーネルバッファの内容をハードディスク上の内容と一致させる処理”であり、“同期的にデータを書き込む処理”ではありません。しかし、本書では説明の複雑化を避けるため、fsync()を呼ぶことも同期書き込み方式として扱います。

(3)
PostgreSQLはデフォルトでautocommit(オートコミット)が有効です。オートコミットの場合、SQL文の実行直後にコミットされるので、通常は(1)(2)が連続して行われます。

(4)
WALログはデータベースクラスタ以下のサブディレクトリ“pg_xlog”に、16[Mbyte] のセグメントファイルとして複数おかれています。

[PREVIOUS][UP][NEXT]