こんにちは、4年目エンジニアの nakaSay です。
本記事では「データベースのきほん」という書籍の内容をかい摘み、いくつかのパートに分けて記事を投稿しています。
本書籍は入門書であり、記事では以下のような内容を取り上げる予定です。気になった方は是非気軽にお立ち寄りください。
- データベースの全体像
- リレーショナルデータベースとは
- データベースに関わるお金の話
- データベースとアーキテクチャ構成
- DBMS を操作するときの基本知識
- SQL文の基本
- トランザクションと同時実行制御
- テーブル設計の基礎
- バックアップとリカバリ
ここでは、DBMSが持つ障害に備えた仕組みについて説明します。
持続性とパフォーマンス
7章でトランザクションのACID特性について取り上げました。
ACIDの「D」はDurability(持続性)で、一連のデータ操作を完了し、完了通知をユーザーが受けた時点で、その操作が「永続的」となり、結果が失われないこと示します。
DBMSがハードディスクに対しデータを保存しますが、ハードディスク上で「持続性」を実現するには、書き込みを全て「同期書き込み」にすれば良いです。
しかし、データベースへの書き込みは記憶装置のランダムな場所にランダムにアクセスして書き込みを行うため、同期書き込みは遅く、パフォーマンス的に実用に耐えないものになってしまいます。
この「持続性」と「パフォーマンス」を両立するために、一般的なDBMSでは以下の仕組みを用いています。
- ログ先行書き込み(WAL: Write Ahead Log)
- データベースバッファ
- クラッシュリカバリ
ログ先行書き込み
ログ先行書き込みの基本的な考え方は、データファイルへ直接書き込みを行わず、まずは「ログ」として変更内容を記述した「ログレコード」を書き込み、同期するという仕組みです。MySQLではこのログを「InnoDBログ」と呼びます。
利点
- ディスクに対して連続的に書き込むため、ランダムに書き込むよりもパフォーマンスが良い
- 複数の書き込みをまとめて行えるため、書き込み回数を減らせる
- データベースバッファ(後述)を利用して、データファイルへの変更を効率よく行える
データベースバッファ
データベースバッファとは、ディスクのデータを一時的に格納し、効率的なデータ操作をサポートするための仕組みです。
一般的なDBMSではデータファイルへの入出力をデータベースバッファ経由に一本化して単純化しています。
MySQLの場合、更新の流れは以下のようになります。
- 更新対象のデータを含むページが、バッファプールにあるかどうか確認され、なければデータファイルからバッファプールに読み込まれる
- 更新がバッファプール内の当該ページに対して行われる
- 2の更新内容が、コミットとともにログに記録される。バッファページで更新したが、まだデータファイルへに書き込まれていないページは、ダーティページとしてバッファプール内で扱われる
- ダーティページは後から適当なタイミングでまとめてデータファイルに書き込まれる(これを「チェックポイント」と呼ぶ)
- 4のチェックポイント以前のログファイルは不要になる。また、更新とともに1から手順が繰り返される
つまりWALとバッファプールが変更を反映していき、データファイルより先んじる形になり、チェックポイントでデータファイルが追いつき、またWALとバッファプールが先行していく、の繰り返しとなります。
クラッシュリカバリ
WALとデータベースバッファ、データファイルの三位一体で持続性を担保しつつ、現実的なパフォーマンスでDBMSは動作しています。
もしクラッシュ(MySQLサーバの異常終了など)した場合は、以下のような状態となります。
- WAL:最後にコミットしたトランザクションの更新情報を持つ
- データベースバッファ:クラッシュにより内容は全て失われる
- データファイル:最後のチェックポイントまでの更新情報を持つ
メモリ上の更新は失われますが、3と1のクラッシュ直前までのログを用いて、クラッシュ時までにコミットされた最新の状態まで戻すことが可能です。
この動作を「ロールフォワード」と呼びます。
バックアップとリカバリ
データベースのデータを様々な障害から守るためには、データベースが正常に動作しているときにバックアップを取得し、障害の後に、そのバックアップを戻します(リストア)。
一般的なDBMSではデータベースに行った更新のログを保持しておき、それをリストアしたデータベースに順次反映することにより、バックアップ時以降の状態にリカバリすることができます。
これを「PITR(Point-in-time recovery)」と呼びます。
バックアップには以下の3つの観点があります。
- ホットバックアップとコールドバックアップ
- 論理バックアップと物理バックアップ
- フルバックアップと部分(増分・差分)バックアップ
ホットバックアップとコールドバックアップ
ホットバックアップ
データベースが稼働したままバックアップデータを取得すること。
MySQL では、トランザクションの仕組みを利用したり、特殊なロックを指定したり、OSやハードウェアのスナップショットを利用して、その時点のスナップショットをバックアップデータとして取得したりする方法があります。、
コールドバックアップ
データベースが停止中にバックアップデータを取得すること。
MySQLでは、データディレクトリ以下のディレクトリとファイルを全てOSのコマンドでコピーする。
論理バックアップと物理バックアップ
論理バックアップ
SQLベースのバックアップで、テキスト形式に準じるフォーマットでバックアップデータが記録される。
- 利点
- テキスト形式なので編集なども可能で移植性(ポータビリティ)に優れており、他のDBMSへもリストアすることができる
- 欠点
- バイナリファイルに比べてサイズが大きくなる。また、バイナリとテキストの相互変換が入るためバックアップ/リストアの動作スピードが遅い
物理バックアップ
データ領域をそのままダンプ(データをファイルや画面に出力)するイメージで、バイナリ形式に準じるフォーマットで記録される
- 利点
- 最小限のサイズで取得でき、データの変換がないのでバックアップ/リストアの動作スピードが速い
- 欠点
- 一部データの変換などは不可能で、プラットフォーム依存のバイナリは、同一のDBMSでも非互換
フルバックアップと部分バックアップ
フルバックアップ
データベース全体のデータをバックアップする方式です。
- 利点
- バックアップデータが1つにまとまっているので、リストア処理が単純
- 欠点
- バックアップにかかる時間が長くなる。また、容量も必要となる
部分バックアップ
一度フルバックアップを取得した後に、その後更新されたデータをバックアップする方式です。
- 利点
- バックアップにかかる時間が少ない。また、容量も少なくて済む
- 欠点
- フルバックアップと部分バックアップが必要となるため、リストアの手順が複雑
部分バックアップには以下の2つの方法がある。
- 差分バックアップ
- 直近のフルバックアップ以降に更新されたデータをバックアップする方法
- 増分バックアップ
- 直近のバックアップ(フルとは限らない)以降に更新されたデータをバックアップする方法
- 容量は少なくて済むが、リストアの際は全てのバックアップを順番に適用する必要がある
まとめ
- データベースはACID特性の「D(持続性)」により、コミットされた内容は永続化され、失われることはない
- サーバやディスクの物理障害などに備えて「バックアップ」の取得が必要
- バックアップの観点には、DBMS停止の有無(コールド/ホット)、フォーマット(論理/物理)、範囲(フル/差分/増分)がある
- バックアップの基本はフルバックアップだが、必要に応じて差分/増分バックアップを検討する
- バックアップにかかる時間と負荷、リストア・リカバリにかかる時間を考慮する
参考