MySQL 5.6におけるsync_binlog=1の改善について&勉強会のお知らせ

2012年6月のエントリの続きです。前回は同期レプリケーションによるネットワーク遅延のある環境において、MySQLの性能がどの程度低下するのかということを確認しました。その中でも特にsync_binlogが1に設定されている場合、性能が大きく低下するということが分かりました。参考としてAmazon RDSのマルチAZデプロイメントにおいては、性能と信頼性のトレードオフを考慮した結果、sync_binlogがデフォルトで0に設定されているということを調査しました。
タイトルでネタバレしていますが、MySQLの次期バージョン、MySQL 5.6でこのsync_binlog=1の性能が大きく改善します。前回と同じ負荷テストをMySQL 5.5.25からMySQL 5.6.6-labsに差し替えて行った結果を、以下に示します。


前回のMySQL 5.5.25と異なり、sync_binlog=1においても多重度に応じたスループットの伸びが確認できると思います。代表的なところで往復遅延時間(Round Trip Time、以下RTT)が4ミリ秒の場合におけるMySQL 5.5.25、5.6.6-labsの結果を並べてみると、以下のようになります。

素晴らしいですね。

バイナリログのグループ・コミット

この性能改善は、バイナリログに対するグループ・コミットという新機能によってもたらされています。グループ・コミットとは、複数のクライアントからのコミット要求をまとめて処理する機能です。
グループ・コミットがない場合、複数のクライアントからのコミット要求は以下のように順番に処理されます。DBMSとしてACIDを満たすため、バイナリログへの書き込みができるスレッドは同時に一つだけとなっています。

今回の環境はディスクに同期書き込み(pwrite(2)+fsync(2))をするところでDRBDによるネットワーク遅延の影響を受け、ここにRTT分の時間が加算されます。RTT 4ミリ秒の場合はコミットに最低でも4ミリ秒かかるため、どんなに頑張っても1秒間に250回しかコミットできないということになります。実際にはこれに合わせてInnoDBログにも同期書き込みをする必要があるため、1秒間にコミットできる回数はさらに減ります。
グループ・コミットがある場合、複数のクライアントからのコミット要求は以下のようにまとめて処理されます。

先に来たコミット要求を処理している間に次のコミット要求が来た場合、ディスクへの同期書き込みを両方まとめて行います。バイナリログへの書き込みができるスレッドが同時に一つだけという点は変わらないのですが、一度のfsync(2)で複数のコミット要求を処理することにより、1秒間にコミットできる回数を大幅に増やすことができます。

グループ・コミットのこれまでの経緯

グループ・コミットはACIDを備えたDBMSであれば基本的にサポートしていることが望ましい機能です。本機能がMySQL 5.6でようやくサポートされるにいたった経緯を確認しておきしょう。
まずInnoDBストレージエンジンの方ですが、こちらは2001年にリリースされたMySQL 3.23の時点ですでにグループ・コミットをサポートしていました。
2005年にリリースされたMySQL 5.0において、バイナリログとInnoDBログの整合性を取るための機能改善が行われました。それまではMySQLサーバがクラッシュした際にタイミングによってバイナリログとInnoDBログの整合性が取れなくなり、レプリケーションスレーブが壊れてしまうことがありました。この機能改善はInnoDB側に2フェーズコミットを行わせるという方針で実装されたのですが、これによってバイナリログ有効時にInnoDBのグループ・コミットが効かなくなるという新たな問題が引き起こされました。

2010年にリリースされたMySQL 5.1+InnoDB Pluginにおいて、sync_binlogが0の場合に限り再びInnoDBのグループ・コミットが効くようになりました。sync_binlogが0の場合は本来の目的であるバイナリログとInnoDBログの整合性を取ることはできないものの、レプリケーションを活用したスケールアウト構成においてマスタの性能を大幅に上げることができるようになりました。

同じく2010年にリリースされたMySQL 5.5において、準同期レプリケーションが導入されました。準同期レプリケーションはグループ・コミットと直接の関係はないのですが、これとMHAを組み合わせることでsync_binlogが0の場合でもマスタ障害によるデータロストやレプリケーションスレーブの不整合を防ぐことができるようになりました。ここまできてようやく性能と信頼性の両方を担保することができるようになったのです。

MySQL 5.6は現在開発マイルストーンが5.6.5まで、実験版が5.6.6-labsまでリリースされています。この5.6.6-labsにおいてついにバイナリログのグループ・コミットが実装されたという次第です。バイナリログのグループ・コミットによってsync_binlog=1における性能が大幅に改善され、共有ストレージやDRBDを用いたクラスタ構成においても、レプリケーションと組み合わせた際の性能と信頼性を両方担保することができるようになります。Amazon RDSでレプリケーションスレーブが壊れて困ったことのある方は、MySQL 5.6の正式版がリリースされてAmazon RDSが対応するまでの辛抱です。

他のDBMSにおけるグループ・コミットのサポート状況

Oracle Databaseははるか昔からグループ・コミットをサポートしていました。ウェブで調べられる範囲では、Oracle 7の時点ですでにサポートされていたことを以下のマニュアルから確認することができます。Oracle 7がリリースされたのは1992年で、いまから20年前のことです。PC-9801FAが初めてi486SXを搭載し、Windows 3.1がリリースされ、Linuxカーネルが0.96だったころの話です。

PostgreSQLは2001年にリリースされたPostgreSQL 7.1でWAL(Write Ahead Logging)が導入され、このときにグループ・コミットもサポートされました。しかし内部の排他制御の設計が適切でなく、これまであまり性能が出ていませんでした。commit_delayというパラメータによってグループ・コミットを発生しやすくすることもできるのですが、こちらの効果も限定的なものでした。
PostgreSQLは次のPostgreSQL 9.2でグループ・コミットの設計が見直され、きちんと性能が出るように改善が図られています。PostgreSQL 9.2は現在ベータ2までリリースされており、順調に行けば2012年中に正式版がリリースされる見込みです。

Oracle Databaseから遅れること20年、MySQLPostgreSQLもようやく…といったところです。

勉強会のお知らせ

話は変わって、2012年7月21日(土)にJPOUG、日本オラクルユーザ会主催のイベントが催されます。

Oracle OpenWorld Unconferenceに引き続きセッション枠をいただいたので、私は「データベース負荷テストツールまとめ(5)」と題して今回のエントリなどで使ったツールの紹介をする予定です。事前に過去4回分をざっと読み返していただくと、当日の話が分かりやすくなると思います。DBサーバのハードウェア、ソフトウェアを調査される方やクラウドサービスの性能評価をされる方、それからパフォーマンス・チューニングの教材を探している方などにおすすめのセッションです。

イベントとしてはOracle Databaseの話が中心となりますが、木村さんMySQLの話、小田さんと林さんがDBエンジニアのキャリアについての話をされるなど、Oracle Database以外の話もいろいろ聞けると思います。オラクル青山センターですのでコーヒーもたくさん飲めます。