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

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

InnoDBには信頼性を高めるための仕組みとして、InnoDBログとバイナリログが存在します。InnoDBログはInnoDBの耐久性を実現する上で必要不可欠なファイルなので使用は必須ですが、バイナリログには使用しないという選択肢もあります。以下、それぞれの概要メモ。

InnoDBログ

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

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

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

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

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

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

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

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

バイナリログ

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

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

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

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

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

おわり

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