DATABASE RECOVERY
DBMSの障害回復とは?データバッファ・WAL・UNDO/REDO・チェックポイントを図解
ネットショップで商品が1個売れた直後に停電。購入者には「注文完了」と表示されたのに、在庫数が元に戻ったら困ります。反対に、まだ購入が完了していない注文が在庫を減らしたままでも困ります。DBMSは、正しく確定した変更を残し、途中の変更を残さないように工夫しています。
- COMMIT は取引の確定を意味する
- REDO は確定済み更新を必要に応じて再適用する
- UNDO は未確定更新の効果を取り除く(方式はDBMSごとに異なる)
1. なぜ「ディスクがあるのに障害回復が必要」なのか
SSDはRAMより遅く、更新のたびにデータファイルへ同期書込みを行うと性能が悪くなります。そのためDBMSは、データの一部分(一般にページ単位)をメモリのデータバッファ/バッファプールに読み込み、そこで更新してから都合のよいタイミングでディスクに書き出します。
① データバッファ
RAM(揮発性)
今まさに読み書きするデータページ。更新後は dirty page(未書出しページ)
② WAL/ジャーナル
メモリ → 永続ストレージ
何をどう変更したか、コミットしたかの記録。書込み順序が重要
③ データファイル
SSD/HDD(永続)
テーブルや索引のページ本体。コミット直後でも旧値のことがある
「バッファを書き換えた」と「ディスクに残った」は別
今見えている更新後の値。停電で消える。
まだ古い値。次の書出しまで一致しないことがある。
ここでコミットした直後に電源が落ちると、RAM上の「8」が消えるかもしれません。ログがなければ、確定したはずの注文を復元できないのです。
2. ログ(ジャーナル)はDBの「作業記録」
DBMSは更新の履歴をログに記録します。一般的には、どのトランザクションが、どのページやデータに、どんな変更を行い、いつコミットしたかを追うための情報です。教科書ではジャーナルファイルとも呼ばれます。
LSNはログの順序を示す番号のイメージ。実際のログ形式や記録内容はDBMSによって異なります。
ログにもログバッファ(RAM)と永続化されたログ(SSD)があります。「ログを作った」だけで安全なのではなく、必要な記録を障害後も残る場所に同期できたかが重要です。
3. WAL(Write-Ahead Logging)を順序で理解する
WALは「データファイルの変更ページを書き出すより先に、それを回復できるログを永続化する」という順序のルールです。更新をデータバッファ上で行うこと自体より、データページのディスク書出しよりログのディスク書出しを先にする点が核心です。
概念的な順序。実際の内部処理ではログ生成とページ更新はより細かく前後・連携することがあります。
厳密には、変更済みページを永続ストレージへ書くより前に、そのページ変更を説明するWALが永続化されていなければならないというのがWALの中心規則です。また、通常の同期コミットでは、コミットを成功として返すために必要なログ記録の永続化を待ちます。設定やDBMSによっては非同期コミットという例外もあります。
間違えやすい二つの発想
- × COMMIT = 全データページがSSDへ書かれた
- ○ COMMIT = トランザクションの永続性を保証するための必要な情報が確保された(標準的な同期コミットの場合)
- × WALなら、未コミットのデータページを絶対に書き出さない
- ○ WALを守れば、未コミットページの書出しを許す実装でも後から回復できる設計が可能
4. REDOとUNDOを在庫数で見分ける
REDO(前進復帰)
T2は在庫を10→8に変更してCOMMIT済み。でもデータファイルには10しかない。
ログを使い、確定済み更新を必要に応じて再適用する。
UNDO(後退復帰)
T3は在庫を20→17に変更したがCOMMIT前に障害。変更がデータファイルに残ってしまった。
未確定更新の効果を取り除き、取引前の状態にする。
これはUNDO/REDO型の一般的な回復モデルでの説明です。REDOをかけるのは「コミット済みの全処理を必ず二重実行する」という意味ではなく、ディスクに未反映の変更を、ログの位置やページ状態を確認しながら必要に応じて再現するという意味です。
「ロールバック」と「UNDO」は同じ?
ロールバックはトランザクションを取り消す操作・概念です。UNDOはそのために更新の効果を元へ戻す処理を指します。試験教材では未コミット取引を「ロールバック対象」と表現しますが、実装では逆向きの物理書換えを常に行うとは限りません。
5. チェックポイントとは「復旧時の出発点」を記録すること
毎回すべてのログを最初から読めば、復旧に時間がかかります。そこでDBMSは、ログとデータファイルの進み具合、回復に必要な位置などをチェックポイントとして記録します。
概念図:回復対象を絞れるため、チェックポイントを設けると再起動のためのログ読み取り量を減らせます。
ここは特に誤解しやすい点です。チェックポイントは、データベース全体をその時刻へ巻き戻すバックアップではありません。 障害時に残っているデータファイルを土台に、必要なログを読み、更新不足や未確定の状態を整えて再開します。
PostgreSQLのチェックポイントでは、その時点までに必要なdirty pageをデータファイルへ書き出し、WALにチェックポイント記録を残します。再起動時はチェックポイント記録が指すredo開始位置などを使います。一方、ARIES系の実装ではファジーチェックポイントとして稼働中のトランザクションやdirty pageの情報を管理し、チェックポイント時点でDB全体を停止・同期するとは限りません。DBMSごとに方式の違いがあります。
6. チェックポイントリスタートを時系列で実演
「チェックポイントを取る → 複数の更新が進む → いきなりクラッシュ → ログを見て復旧」という流れを、在庫A・Bの数値で追います。
10:00
チェックポイント完了
ここまでに必要な変更ページが保存されたとする
10:01
T2 が商品Aを 10 → 8 に更新
ログを記録、バッファを更新。まだデータファイルは10のままでもよい
10:02
T2 を COMMIT
コミットの永続性に必要なログを同期。データページの書出しは後でもよい
10:03
T3 が商品Bを 20 → 17 に更新
T3 は未コミット。変更ページがディスクへ出る構成もある
10:04
電源断
バッファは消失。ログとデータファイルから回復処理を始める
再起動すると何が起きる?
- 最後の有効なチェックポイント情報と回復用ログを確認する。
- ログからコミット済み取引と障害時に未完了の取引を把握する。
- 必要なデータページの更新をREDOして、確定した更新を失わないようにする。
- 未コミット取引の効果をUNDOする(UNDO型のDBMSの場合)。
- 一貫した状態を確認し、新規処理を再開する。
図では、T2の在庫Aは8へ回復し、T3の在庫Bは20へ戻ります。ここで「T2はコミット済み」「T3は未コミット」が判断の軸です。データページがいつディスクに書かれたかにより、実際に再適用・取消しすべき記録は変わります。
7. 試験でよく見るT1〜T6の読み方
添付の題材では、チェックポイント前にコミットしたT1、チェックポイント後にコミットしたT2・T5、障害時に未完了のT3・T4・T6を見分けます。ただし、T3・T4は読取りだけでデータ更新がないため、復旧時に取り消す更新がありません。
| 取引 | 状態 | 回復上の扱い |
|---|---|---|
| T1 | チェックポイント前にCOMMIT | 通常は追加処理不要(題材の前提) |
| T2 / T5 | チェックポイント後にCOMMIT | REDOの対象 |
| T3 / T4 | 障害時未コミット・読取り専用 | 取り消す更新なし |
| T6 | 障害時未コミット・更新あり | UNDOの対象 |
これは、チェックポイント以前の確定済み変更がディスクへ反映済みとする設問の単純化モデルです。実際のDBMSでは、回復開始位置やトランザクション管理情報を考慮して再適用・取消しの要否を判断します。
8. WALならどのDBMSでもUNDOログがある?
いいえ。WALは「ログ先行」の規則であって、UNDOの具体的な方式まで1種類に決めるものではありません。
教科書・ARIES系のモデル
更新前の情報などで未コミット更新をUNDOし、必要な変更をREDOする。ページの書出しとコミットを分離できる。
PostgreSQLのMVCC
WALによるREDOと、トランザクションの可視性制御を組み合わせる。未コミットの行バージョンを必ず旧値に物理UNDOするわけではない。
また、SQLiteのWALモードでは、更新をWALに追加し、後からチェックポイントで本体へ反映するという設計です。共通の考え方は「障害後にも残る記録を先に確保する」ことで、データページの管理方法はDBMSごとに異なります。
9. WALはバックアップの代わりになる?
WALと障害回復は、主に突然のプロセス停止や電源断への対策です。SSDそのものが故障し、データファイルもログも失われた場合、同じディスク上のWALだけでは復旧できません。別ストレージへのバックアップ、ログ保管、復元手順の検証が必要です。
さらにWALだけでなく、ディスクやOSの書込み保証、同期設定、ファイルシステムの特性なども耐久性に関係します。ログを記録しただけで、あらゆる故障に無条件で耐えられるわけではありません。
10. 操作ラボ:停電の瞬間を変えて復旧する
次のラボでは、在庫数を例にバッファ・ディスク・ログの値の違いを実際に切り替えます。コミット済みデータが未書出しの場合はREDO、未コミットの更新がすでに書き出されている場合はUNDOが必要になることを確認してください。
在庫更新中に停電!DBはどう復旧する?
3つの場面から選び、次へ進めてください。これは「UNDO/REDO型DBMSの概念模型」です。
確定済みなのに本体未反映のT2と、未確定なのに本体反映済みのT3が混在。
RAM:データバッファ
在庫A(T2)
10
在庫B(T3)
20
SSD:データファイル
在庫A(T2)
10
在庫B(T3)
20
SSD:永続WAL
在庫A(T2)
未同期
在庫B(T3)
未同期
① チェックポイント後
最後のチェックポイントが示す回復用ログ位置から、必要な範囲を調査できます。
チェックポイントは「その時点のバックアップへ必ず戻す」という意味ではありません。
注:実製品ごとの実装差を省略しています。ログの永続化、コミット応答、実際のページflush順序は製品と設定によって異なります。上の「送出済み未コミット」はsteal + WALモデルの説明です。
11. まとめ
- データバッファはRAM上の作業場所。ディスクへの反映は遅れることがある。
- ジャーナル/ログは変更や確定状況を残す記録。ログバッファと永続ログを区別する。
- WALは、変更ページの書出しより先に必要なログを永続化する規則。
- REDOは未反映の確定済み更新を再現する。
- UNDOは未確定更新の効果を取り除く。方式はDBMSによって違う。
- チェックポイントリスタートは、チェックポイント情報を手掛かりにログを調べ、必要な回復だけ行って再開する考え方。
参考:PostgreSQL公式ドキュメント(WAL/チェックポイント)、SQLite公式WAL文書、ARIES論文。図や操作ラボは「更新前・更新後ログを使うUNDO/REDO型」を簡略化した学習モデルであり、各製品の内部実装を完全再現するものではありません。