読者です 読者をやめる 読者になる 読者になる

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

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

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

InnoDBログ

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

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

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

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

この問題を解決するために、一旦は書き込みにコストがかからないバッファプールとInnoDBログに書き込みを行って、適当なタイミングで裏で走っているスレッドがその情報をテーブルスペースに反映させるという方法をとっています。
書き込みの回数はバッファプール、InnoDBログ→テーブルスペースと2段に増えますが、InnoDBログへの書き込みはシーケンシャルライトになるため高速なので、コストはそこまで問題になっていないようです。

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

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

バイナリログ

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

レプリケーションでは、マスタの変更をスレーブに反映させる必要がありますが、その反映にバイナリログを使用します。
マスタは定期的にスレーブにバイナリログを送信して、バイナリログを受信したスレーブは書かれている更新内容を自身に反映させます。
スレーブが反映作業中に落ちてしまうと、再起動後に次はバイナリログのどこから反映作業を再開すればいいのか、どこまで終わっていたのかが分からなくなってしまいます。
これを回避するために、バイナリログをどこまで実行したかという情報を保持しておくためのテーブルが用意されています。

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

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

おわり

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