MySQL バイナリログとInnoDBログについて調べたメモ

MySQLのストレージエンジンであるInnoDBに備わっているバイナリログとInnoDBログについてよく分からなかったので軽く触れてみることにしましたが、ちょっと情報が古いかもしれません。

InnoDBには、InnoDBログとバイナリログが存在します。InnoDBログはInnoDBの耐久性を実現する上で必要不可欠なファイルなので使用は必須です。バイナリログは使用しないという選択肢もあります。

InnoDBログ

クラッシュリカバリで使用されるファイルです。InnoDBでデータ更新時に発生するフローを簡単に書くと以下のような流れになります。

InnoDBログへ更新情報の書き込み
②バッファプールへの更新情報の書き込み
③適当なタイミングでバッファプールの情報をテーブルスペースへの反映

InnoDBでは、コミットと同時に直接ディスクに対してデータ更新処理や取得処理をするようになっていません。バッファプールと呼ばれる領域(ディスクキャッシュ)に一度読み込まれたデータが格納されていて、読み込みはもちろん書き込みもこの領域で行います。バッファプールで更新された情報は、後で適切なタイミングでテーブルスペース(ディスク)に反映されるようになっています。

コミットと同時に直接ディスクに対してデータ更新処理をあてていないのは、書き込み性能を上げるためです。データを更新する際にはインデックスツリーの更新が必要であったり、更新対象がテーブルスペース内のいろいろな所に分散していてランダムアクセスが発生したりします。つまり、ディスクのあちこちを行ったり来たりして内容を弄る必要があるので、シーク時間的な意味で効率が良くないのです。

この問題を解決するために、メイン処理として一旦は書き込みにコストがかからないバッファプールとInnoDBログに書き込んで、適当なタイミングで裏で走っているスレッドがその情報をテーブルスペースに反映させるという方法をとっています。コストがかかる処理をオフライン化しているという感じだと思います。

書き込みの回数は[バッファプールやInnoDBログ]→[テーブルスペース]となるのでワンステップ増えますが、InnoDBログへの書き込みはシーケンシャルライトになるため高速なので、コストはそこまで問題になっていないようです。

この方式の問題は、バッファプールとテーブルスペースとで整合性がとれていない時間が存在するというものです。その整合性がとれていない時間、つまりバッファプールからテーブルスペースへのデータの反映が行われていない時に例えば電源が落ちてしまったりすると、バッファプールに格納されていたデータは消えてしまい、再起動後に消えたデータの復旧をしようと思ってもできなくなってしまいます。

InnoDBログはこのような状況に陥った際に使用されるファイルで、上記問題を解決します。バッファプールとInnoDBログは同期されているので、InnoDBログのデータをテーブルスペースに反映していけばデータが消える前の状態までデータを復旧させることが出来ます。

バイナリログ

こちらもデータの更新が行われるとその更新情報が記録されるファイルです。InnoDBログと似ていますが、バイナリログはロールフォワードリカバリレプリケーションに使用されるファイルです。

レプリケーションでは、マスタの変更をスレーブに反映させる必要がありますが、その反映にバイナリログを使用します。マスタは定期的にスレーブにバイナリログを送信して、バイナリログを受信したスレーブは書かれている更新内容を自身に反映させます。

しかし、スレーブが反映作業中に落ちてしまうと、再起動後に次はバイナリログのどこから反映作業を再開すればいいのか、どこまで終わっていたのかが分からなくなってしまいます。これを回避するために、バイナリログをどこまで実行したかという情報を保持しておくためのテーブルが用意されています。

ロールフォワードリカバリでは障害直前の状態までデータを復旧させる必要がありますが、これにもバイナリログを使用します。リカバリをする場合は、まず定期的にとっているであろうバックアップを使用して特定のバックアップ時点まで戻します(リストア)。しかし、これだけではバックアップをとった時点以降のデータ更新情報が反映されていません。そこで、リストアした後にバイナリログに記録されている更新情報を反映させていけば、障害直前の状態まで復旧することが出来ます。これがロールフォワードです。

バイナリログへの書き込みもデフォルトではディスクと同期されないので、障害が起きて落ちてしまったりすると、ディスクは最新の状態でバイナリログは最新の状態ではないということが起こり得ます。設定することで同期させることも可能ですが、更新の速度が遅くなるのでここはトレードオフになります。

おわり

InnoDBログは障害が発生した時に障害発生前のバッファプールの情報を復旧させるために使用するもの(クラッシュリカバリ)で、バイナリログは障害が発生した時に障害発生前の特定時点までデータを戻すために使用するもの(ポイントインタイムリカバリ)、という認識でいいのかどうかわかりませんが、僕はそんな感じだと思ってます。