MySQL 5.6の InnoDB バッファープールのプリロード機能が優秀で頭悪いクエリを投げなくても良くなった
再起動を高速化するための InnoDB バッファープールのプリロード
特に大きなバッファプールを扱う場合にMySQLを再起動すると、起動直後はメモリにDBのデータが乗っていないので大きなディスクIOが必要になるようなイカれたクエリを投げるとめちゃくちゃ遅いという現象が起きます。
MySQL5.5以前はユーザリクエストを振る前にイカれたクエリを実行しておくことでバッファプールに乗せるという手法がそれなりに有効でした。
ただ、イカれたクエリを投げる方法ではバッファプールが再起動前と同じ状態になるわけではないので遅いクエリはどうしても出てしまうし、再起動前に近い状態になるにはそれなりに長い時間が必要でした。
InnoDB バッファプールのプリロード機能は、バッファプールの復元に必要な情報をファイルから復元することでバッファプールを再起動前の状態に復元できる機能です。
バッファプール復元のための情報は終了時か任意のタイミングでファイルに書き出せます。バッファプールの中身をすべて書き出すわけではないので、それほどディスクを圧迫することはありませんし、IO負荷も少なめです。
ファイルにはテーブルスペースIDとページのIDが書き出されます。
シャットダウン時にバッファプールを書き出すには SET GLOBAL innodb_buffer_pool_dump_at_shutdown=ON;
を実行しておきます。
すぐに書き出すには SET GLOBAL innodb_buffer_pool_dump_now=ON;
とするだけです。
デフォルトではデータディレクトリに ib_buffer_pool
という名前で保存されます。
データディレクトリに ib_buffer_pool
がある状態で SET GLOBAL innodb_buffer_pool_load_now=ON;
を実行すると、バッファプールの復元が始まります。
ib_buffer_pool
はテーブルスペースIDとページIDを記録しているだけなので、他のサーバで生成したものを使うこともできます。
(innodb_buffer_pool_sizeが違っていても動作します。メモリから溢れるだけかな・・・いや嘘ですわかりません適当なこと書きました)
(できそうな気はしてたので検索したらやってる方がいました。)
これが便利で 本運用しているデータベースサーバで ib_buffer_pool
を書き出し -> 再起動済みのデータベースサーバにコピー -> バッファプールのロード と実行すれば、
本運用しているサーバと同じようなバッファプールの状態が復元でき、いきなりイカれたクエリが飛んできてもそれなりに高速に処理できるようになっています。
ウォームアップのためにイカれたクエリを投げなくてもよくなって平和になりました。
メモリやSSDも数年前と比べ安価で高速になり大規模データベースを扱いやすくなっていますね。大きなバッファプールを扱わないといけない機会が辛いめでたい。
free -h のことをフリーエッチとかいうのよくない
— シリル@ひだまりPHP 3日目西f26a (@d_cyrill1129) July 27, 2016