DBアタマアカデミー

第2回 トランザクションを知ればデータベースがわかる―「データ復旧」「同時実行制御」を行う“不完全な”しくみ(2)

この記事を読むのに必要な時間:およそ 2 分

トランザクションが「終わる」のはいつか

ところで,前回で私は,障害発生前に終了しているトランザクションの変更は救う』というのが耐久性(D)の定義だ」と述べましたが,このときの「終了している」とはどういう意味なのでしょう。言い換えると,トランザクションは,いったいいつ「終わる」のでしょう。

COMMIT/ROLLBACKには時間がかかる

直観的に考えれば,それは「COMMIT(またはROLLBACK)が実行されたとき」です。そして,ここにおいて私たちとDBMSとの間に認識のズレはありません。障害発生前にCOMMITまでたどり着いたトランザクションは,障害後にも救われます。そんなの当たり前のことではないか,と思うかもしれませんが,DBMSの内部処理という観点から見ると,ここにはクリアすべき問題があるのです。

もしトランザクションが,物理的にデータファイルへすべての変更を反映し終わったタイミングをもって「終わり」と判断されるならば,特に問題はありません。データは堅固なディスクに保存されているため,たとえDBMSに障害が発生しても,再起動すればトランザクションが変更したあとのデータが生き残っています(仮にディスクに物理的な障害が起きた場合でも,冗長化などの対策がとられていればデータは救われます)⁠

しかし,本連載の第1回で見たように,実際には多くのDBMSは,データファイルへ変更を反映する前に,トランザクションの終了をユーザに通知しています。そうすると,COMMITが発行されたあとで,かつ,データファイルへ変更が反映される前に障害が発生した場合,トランザクションのデータは失われてしまうことにならないでしょうか? もしそうなら,ACIDの「D」を満たさないことになる深刻な事態です。

WALでひとまずログファイルに書き込む

現実には,それは起こりません。この損失を防止するためにDBMSが備えているしくみが,一般にWALwrite-ahead logと呼ばれている方法です。日本語ではログ先行書き込みと訳します。名前のとおり,COMMIT時にデータファイルにすべての変更を反映する代わりに,ログファイル(⁠ジャーナルファイル」とも呼びます)に当該トランザクションで行われた操作の記録を書き出す方法です。これは,データファイルに変更を書き込むよりずっと書き込み量が少ないので,短時間で終わります注3)⁠余談ですが,WAL はWindows のNTFSNT File SystemやLinuxといったファイルシステムでも用いられていて,ジャーナリングjournalingと呼ばれています。

DBMSは,COMMIT時にはいったんログファイルに操作ログだけ残しておいて,データファイルへの変更反映は後でゆっくりやっているのです(このデータファイルへの反映処理をチェックポイントと呼びます)⁠実装によっては,ログファイルに操作コマンドだけでなく,変更前・変更後のデータを直接保持するようなしくみを持つ場合もありますが,それでもデータファイルに比べればログファイルのサイズはずっと小さなものになります図2)⁠

図2 WALのしくみ

図2 WALのしくみ

WALによって,COMMITしてから変更がデータファイルに書き込まれるまでに障害が発生した場合でも,ログファイルさえ残っていれば,DBMSの再起動時にそのログを参照して,もう一度自動的にトランザクションを再実行すれば変更を正しく反映することが可能になるのです。この再実行処理を,ロールフォワードと呼びます。ちょうどロールバックの反対語です。もちろん,こんな面倒なことをせず,COMMIT時にいきなりデータファイルを更新してしまえばずっとしくみは簡単になるのですが,それだと巨大なデータファイルの更新コストが大きいため,COMMIT時にユーザを長く待たせることになってしまうのです。ここでも支配者はトレードオフの原則です注4)⁠

注3)
「WALを使用することでディスクへの書き込み回数が大幅に減少します。と言うのも,トランザクションがコミットされたことを保証するために,そのトランザクションで変更された全てのデータファイルではなく,ログファイルだけをディスクに吐き出す必要があるからからです。」第28章信頼性とログ先行書き込み」『PostgreSQL 8.4.4 文書』

障害発生時のトランザクション状態と復旧時の動作

具体的に,図3のような5つのトランザクションのケースを考えてみましょう。

図3 トランザクションの状態と障害発生

図3 トランザクションの状態と障害発生

『データベースシステム概論 第6版』P.413の図を引用

今,時刻Tmで不運にもDBMSが障害に見舞われシステムがクラッシュしました。幸い物理障害ではなかったため,DBMSの再起動は無事行うことができました。さて,T1~5の結果はどのようになるでしょうか。

まず,簡単にわかるところとしては,T1はまったく何の問題もなく結果が保証されます。T1は,チェックポイントでデータファイルに同期済みのため,再起動時に何の処理も行う必要がありません

時刻Tmでトランザクションが実行中だったT3とT5は残念な結果になります。再起動時にロールバックによって「なかったこと」とされてしまうのです。ログファイルが完全ではないためロールフォワードもできないので,ユーザが手動で再実行するしかありません。

注目すべきがT2とT4です。この2つは,障害前にトランザクションが終了しているため,結果は保証の対象となります。ただし,T1と違って,チェックポイントより後にもトランザクションが実行されているため,データファイルはまだ同期されていません。変更履歴が残っているのはログファイルだけですので,再起動時にロールフォワードが実施されます。障害があってDBMSを再起動するとき,いつもより余計に時間がかかることがありますが,それは裏で上述のようなロールバック/ロールフォワードが行われているからです。

このように,DBMSは常に処理のログを記録して残しておくことで,障害時においてもトランザクションの結果を保証できるわけです。このことを,コンピュータ科学者のJim Grayは「ログは何でも知っている」という印象的な言葉で表現しました。

データベースの基本精神
ログは何でも知っている。
注4)
トレードオフについては本連載第1回で詳しく解説しています。

著者プロフィール

ミック

SI企業に勤務するDBエンジニア。主にデータウェアハウス業務に従事している。自身のサイト「リレーショナル・データベースの世界」でデータベースとSQLについての技術情報を公開している。『Web+DB Press』で「SQLアタマアカデミー」を連載中。

著書:『SQL ゼロからはじめるデータベース操作』(翔泳社,2010)『達人に学ぶ SQL徹底指南書』(翔泳社,2008)訳書:J.セルコ『SQLパズル 第2版』(翔泳社,2007)

DBアタマアカデミー:サポートページ

コメント

  • Re:

    コミットとチェックポイントでの処理の違いが分かりやすく書かれているものがなかなか見つからず、理解できずにいたのですが、ロールバックとロールフォアードの違いとともにこのHPを読んで理解することができました。
    とてもわかりやすかったです。
    ありがとうございました。

    Commented : #1  長船 翔太 (2016/03/12, 18:39)

コメントの記入