レプリケーションがクラッシュセーフとはどういうことか
クラッシュセーフとは、何らかの事情により、プロセスがダウンしたりマシンが電源ごと落ちたり(つまりクラッシュ)しても、再起動後に以前の状態に戻って処理を再開できるということだ。データのクラッシュリカバリであればみなさん既によくご存知であろう。(REDOやUNDOするアレのことだ。本稿では面倒臭い・・・ではなかった、本題ではないため詳細は省略する。)MySQLのレプリケーションがクラッシュセーフであるとは、マスターあるいはスレーブ、もしくは両方がクラッシュしても、再起動後に設定をいじったりデータを修復したりすることなくレプリケーションを再開できるということだ。ちなみに、これはマスターとスレーブの関係性はそのままで、スレーブを昇格させたりするわけではなく、単に再起動だけで対処する場合の話である。
マスターがクラッシュセーフになるためには次の3つの要件を満たす必要がある。
- バイナリログが破損しないこと。
- スレーブへ送信するイベントは、バイナリログへの書き込みとディスクへの同期が完了したものであること。
- DMLがクラッシュセーフであること。
スレーブがクラッシュセーフになるための要件は次の通り。
- クラッシュしてもスレーブのデータとレプリケーションの設定情報がズレないこと
- リレーログが破損した場合にはマスターから読み直すこと。
以前のバージョンでは、レプリケーションの設定情報はファイルに書かれていたため、どうしてもクラッシュセーフにすることはできなかった。ファイルの更新はトランザクションに含めることができないからだ。MySQL 5.6から、レプリケーションの情報をテーブルに格納することができるようになったため、クラッシュセーフになったわけである。リレーログはファイルなのでデータと同期させることはできないが、万が一壊れてしまっても、単にマスターから読みなおせば良いので問題はない。
レプリケーションがクラッシュセーフだと何が嬉しいのか
いや、そりゃあもう嬉しいに決まってる。なんせ、クラッシュセーフでなければ、クラッシュしたらレプリケーションを再セットアップしなければならない羽目になるのだから。再セットアップとは、つまりマスターか他のスレーブからデータをバックアップし、コピーしてくることだ。その際、データと完全に一致したレプリケーションの開始位置(バイナリログファイル名とポジション)を取得する必要がある。データサイズにもよるが、データを完全にバックアップ+リストアするのは骨が折れる作業だ。オンラインでバックアップをとったとしてもかなりのI/Oが発生するので負荷が低い時間帯を狙って作業する必要があるし、時間もかなりかかる。
スレーブが複数あれば、クラッシュセーフでないスレーブを修復するのは少し簡単になる。スレーブのうちひとつを落としても良いのならバックアップはオンラインで無くて良い。その場合、他のスレーブをコールドバックアップして、レプリケーションの設定とデータをコピーすれば済む。
スレーブがたくさんある場合でも、マスターがクラッシュした場合は厄介だ。バイナリログから最後のイベントが喪失してしまうと、最悪全てのスレーブがマスターとずれてしまうからだ。スレーブがクラッシュしたときはスレーブがたくさんあると有利だが、マスターがクラッシュしたときはスレーブがたくさんあることで返って余計に手間が増えてしまう。マスターを復旧するよりスレーブを昇格させたほうが手間がかからないケースも少なくない。マスターがクラッシュリカバリを完了するまでの時間のロスを考えると、むしろスレーブを昇格させるほうが現実的ですらある。その場合、マスターは新たなスレーブとなるが、他のスレーブとはデータがズレている可能性があるので、再セットアップ(他のスレーブ等からデータをコピーする)作業が必要となる。
このように、クラッシュセーフでないことが、レプリケーションを運用する上で最大のリスクであった。だが、MySQL 5.6ではそれが解消されているわけである。もしまだMySQL 5.5以前のバージョンでレプリケーションを使用しているのであれば、ぜひMySQL 5.6へのアップグレードを検討して頂きたい。クラッシュ時の復旧作業の手間がガラリと変わるはずだ。
マスターの設定
マスターがクラッシュセーフであるための条件は先程書いた。まず、DMLがクラッシュセーフであるためには、使用するストレージエンジンはInnoDBでなければならない。InnoDBも設定によってはクラッシュセーフでない使い方もできるが、レプリケーションをクラッシュセーフにしたければ、InnoDBもそうでなければならない。基本的にデフォルトの設定はクラッシュセーフなので、次のようなことをしないようにする必要がある。- innodb_flush_trx_commitは1以外にしない。
- ダブルライトを無効化しない。(ただしアトミックな書き込みが可能なファイルシステムを使用している場合はこの限りではない。)
そして、バイナリログの安全性については、sync_binlog=1を設定すれば良い。この設定により、バイナリログとストレージエンジン内のデータが同期することが保証される。万が一クラッシュ時にバイナリログが欠損してしまったり、バイナリログとデータがズレてしまった場合には、クラッシュリカバリにおいて帳尻が合わされる。
もうひとつ、非常に重要な要件は、MySQL 5.6.17以降のバージョンを使うことである。バイナリログへの同期より先にスレーブへイベントを送信してしまうバグの影響で、マスターがクラッシュすると、マスターとスレーブのデータがズレてしまうからだ。
スレーブの設定
スレーブをクラッシュセーフにするには、データとレプリケーションの設定情報がズレないようにする必要がある。そのために、まず、relay_log_info_repository=TABLEを設定する。そして、リレーログに問題があったときにマスターから自動的に読みなおすために、relay_log_recovery=ONを設定する。スレーブのレプリケーションをクラッシュセーフにすると、mysql.slave_relay_log_infoというテーブルにリレーログの情報が記録されるようになる。間違ってDROPやTRUNCATEなどしてしまわないように気をつけよう。
制限事項
レプリケーションがクラッシュセーフになると言っても、そうはならないケースがいくつかある。まず、レプリケーションがクラッシュセーフであるためには、元の処理もクラッシュセーフでなければならない。従って必然的にクラッシュセーフになるストレージエンジンはInnoDBだけに限られる。MyISAMはクラッシュセーフでないので、その点を覚悟した上で使用しなければならない。あえてジョジョ風に言えば
あなた…『覚悟して来てる人』……ですよね。ということになる。データを失いたくないのであればMyISAMを使用するのは止めておくべきだろう。OLTPではなく分析用であればMyISAMでも問題ないかも知れない。ただし、万が一データが壊れても、他のテーブルのデータからMyISAM内のデータを再作成できる場合に限られる。
MyISAMを使おうとするって事は、
クラッシュでデータが破損するかもしれないという危険を、
常に『覚悟して来ている人』ってわけですよね…
また、MySQLを使う上でどうしてもMyISAMの使用が避けられない箇所としては、システムテーブルが挙げられる。特に権限情報を格納するテーブルはMyISAMなので、間接的にそれらを更新するGRANTコマンドはクラッシュセーフではない。権限の付与などをする場合には事前にしっかりとバックアップを取っておくようにしよう。
実は、MySQLはDDLもクラッシュセーフではない。テーブルのメタデータは.frmファイルに格納されているのだが、InnoDBが管理していないファイルへの更新はトランザクションに含めることが出来ないからだ。ちなみに、これがMySQL 5.7に向けて新しいデータディクショナリを実装している理由である。MySQL 5.7ではこの辺が改良されれば、レプリケーションがより強固になると考えられるが、現状はそうではないので、DDLを実行する前には必ずバックアップを取るような運用を心がけよう。
マスターからスレーブへ向けてのレプリケーションはクラッシュセーフにすることができるが、スレーブを昇格させたときは、元のマスターのデータはズレてしまうかも知れない。というのも、マスターからスレーブへのデータ転送が完了する前に、マスターはバイナリログをディスクへ同期するため、タイミングによってはマスターのほうが進んでしまう場合があるからだ。従って、スレーブを昇格させる場合には、マスターのデータは一旦破棄して、再度コピーするのが安全である。その手間が惜しいなら、マスターの再起動を待ったほうが良いだろう。
繰り返しになるが、バグがあるためマスターがクラッシュセーフになるのはMySQL 5.6.17以降である。MySQL 5.6.17も割と古いので、どうせなら最新バージョンを使うようにしよう。
0 件のコメント:
コメントを投稿