はじめに
MariaDB 12.3.1 での追加された新機能、バイナリログを従来の独立したファイルではなくInnoDBのテーブルスペース内に保存する「InnoDB-Based Binary Log」をご存知でしょうか。
長い間、バイナリログはパフォーマンスのボトルネックとなってきました。
従来、MariaDBはバイナリログとInnoDBストレージエンジンを別々のコンポーネントとして扱い、両者を同期させるために複雑な2フェーズコミットを必要としていました。
今回の新しいバイナリログ実装では、バイナリログとInnoDB間の高コストな2フェーズコミットが不要になり、パフォーマンスが大幅に向上し、クラッシュリカバリ動作も簡素化されます。
本記事では、sysbenchを用いたベンチマーク結果を交え、その性能向上の実態についてご報告いたします!
従来のバイナリログが抱えていた「2フェーズコミットの壁」
まず、そもそもアーキテクチャがどのように変わったのか確認したいと思います。
従来のファイルフォーマットのバイナリログでは、クラッシュ時の安全性を保証するためには sync_binlog=1 かつ innodb_flush_log_at_trx_commit=1を設定し、トランザクションのコミットのたびにInnoDBのWAL(Redoログ)とバイナリログの両方でディスク同期書き込み(fsync())を行う必要がありました。
sync_binlog=1
→ 各トランザクションの バイナリログ 書き込みごとに ディスクに同期します
→ クラッシュ時にバイナリログの書き込み漏れを防ぐ。
innodb_flush_log_at_trx_commit=1
→ コミットごとに REDOログ をディスクに同期します
→ InnoDB のデータ永続性(クラッシュリカバリ対象)を保証。
これにより、InnoDBとバイナリログという 2つの独立したリソース間でデータの整合性を保つための2フェーズコミットにより、コミットのたびにディスク同期の待機が2回発生していました。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[ BEGIN transaction ] │ ├─▶ InnoDB: Undoログ書き込み(Redoログへ記録) │ ├─▶ InnoDB: Prepare段階 (XA prepare, Redoログへ記録) │ ├─▶ Binlog: 独立したバイナリログファイルへイベント書き込み │ ├─▶ Binlog: 待機【 fsync() 1回目 】 ◁ sync_binlog=1 によるディスク同期 │ ├─▶ InnoDB: Commit (Redoログへコミットレコード書き込み) │ ├─▶ InnoDB: 待機【 fsync() 2回目 】 ◁ innodb_flush_log_at_trx_commit=1 によるディスク同期 │ [ COMMIT 完了 ] |
InnoDBフォーマットのバイナリログではどう変わるのか?
今回、MariaDB 12.3.1 で追加されたInnoDBフォーマットのバイナリログでは、イベントが InnoDB(.ibbファイル)に書き込まれるようになり、2フェーズコミットが排除されました。
|
1 2 3 4 5 6 7 8 |
[ BEGIN transaction ] │ ├─▶ InnoDB: Undoログ + Binlogイベントを統合して書き込み (単一のRedoログとして記録) │ ├─▶ InnoDB: 待機【 fsync() 1回のみ 】 ◁ innodb_flush_log_at_trx_commit=1 によるディスク同期 │ [ COMMIT 完了 ] |
sync_binlogパラメータは実質的に無視され、コミットの永続性は innodb-flush-log-at-trx-commitパラメータによってのみ制御されるようになります。
呼び出すべき fsync() が1回で済むようになったことで同期待ちの時間が半減し、InnoDB内部でのグループコミットもより効果的に機能するようになります。
つまり、InnoDBフォーマットのバイナリログは、ただ設定を変えたのではなく MariaDBのコミットパイプライン自体の再設計(2フェーズコミットの排除) ということになります。
また、バイナリログ自体がInnoDBの内部に統合されているため、クラッシュ時でもデータとバイナリログが乖離することは原理的に起こり得ず、整合性が保たれる設計となります。
設定方法
my.cnfなどの設定ファイルに下記設定を加えて再起動するだけです。
|
1 2 3 4 |
[mysqld] log_bin binlog_storage_engine=innodb |
設定上の注意点ですが、 log_binパラメータでは引数(ファイル名)を指定できません。
これはInooDBフォーマットの場合、ファイル名は binlog-000000.ibbで固定されているためです。(ファイル名は、バイナリログがローテションするたび 000000 の部分がカウントアップ)
また、効率化のため常にバイナリログは 2つ生成されるため、デフォルトでは 1GB × 2つ = 計2GBのバイナリログが生成されます。(基本的には バイナリログファイルはmax-binlog-sizeのバイト数と正確に一致します)
|
1 2 3 4 |
$ ls -lh /var/lib/mysql/binlog-00000* -rw-rw----. 1 mysql mysql 1.0G Mar 31 06:09 /var/lib/mysql/binlog-000000.ibb -rw-rw----. 1 mysql mysql 1.0G Mar 27 09:34 /var/lib/mysql/binlog-000001.ibb |
パフォーマンス検証
検証環境
今回のベンチマーク検証は、以下の環境および条件で実施しました。
- サーバースペック
- インフラ: Oracle Cloud Infrastructure コンピュートインスタンス
- シェイプ:VM.Standard.E5.Flex
- CPU: 2 OCPU (4 ECPU / vCPU相当)
- メモリ: 16 GB
- ストレージ: ブロックボリューム 200 GB (最大IOPS: 15,000 最大スループット: 120 MB/秒)
- インフラ: Oracle Cloud Infrastructure コンピュートインスタンス
- ベンチマークツール
- ツール: sysbench (v1.0.x系)
- ワークロード: oltp_write_only (更新系のみのトランザクション)
- データサイズ: 1,000万件 (100万件 × 10テーブル)
- ツール: sysbench (v1.0.x系)
ベンチマークの実行 では16スレッドの並列接続で、更新系クエリを600秒間(10分間)実行し、TPS(Transaction Per Second)やQPS(Query Per Second)を測定します。
計測結果
詳細な考察については後述しますが、やはりInnodbフォーマット(Case1~3)にすることでディスク同期の回数が少なく分、従来のファイルフォーマット(Case4~Case9)と比較するとスループットの向上が確認できました。
| ケース | binlog_storage_engine | sync_binlog | innodb_flush_log_at_trx_commit | TPS | QPS |
|---|---|---|---|---|---|
| Case1 | innodb (新) | (不要) | 0 | 6,941 | 41,651 |
| Case2 | innodb (新) | (不要) | 1 | 5,313 | 31,880 |
| Case3 | innodb (新) | (不要) | 2 | 7,107 | 42,643 |
| Case4 | file (旧) | 0 | 0 | 6,567 | 39,406 |
| Case5 | file (旧) | 0 | 1 | 4,190 | 25,143 |
| Case6 | file (旧) | 0 | 2 | 6,962 | 41,776 |
| Case7 | file (旧) | 1 | 0 | 3,817 | 22,902 |
| Case8 | file (旧) | 1 | 1 | 2,849 | 17,099 |
| Case9 | file (旧) | 1 | 2 | 3,762 | 22,576 |
結果サマリ
DBでは、データの安全性を確保した状態で、どれだけスループットが出せるのかが重要なポイントになってきます。
今回は、データ保護を保証する設定( innodb_flush_log_at_trx_commit=1)でのパターン(Case2、Case5、Case8)に重点をおいて、検証結果を考察していきたいと思います。
1. 安全性設定時の性能比較(InnoDB:Case 2 vs File:Case 8、Case5)
| ケース | binlog_storage_engine | sync_binlog | innodb_flush_log_at_trx_commit | TPS | QPS |
|---|---|---|---|---|---|
| Case2 | innodb (新) | (不要) | 1 | 5,313 | 31,880 |
| Case5 | file (旧) | 0 | 1 | 4,190 | 25,143 |
| Case8 | file (旧) | 1 | 1 | 2,849 | 17,099 |
従来のファイルフォーマットのバイナリログでクラッシュ時のデータの安全性を保証するには、sync_binlog=1 と innodb_flush_log_at_trx_commit=1 の両方を設定する必要がありました(Case 8)。
この時のTPSは 2,849 と最も低い結果になっています。
このケースでは、トランザクションのコミットのたびにInnoDBのWAL(Redoログ)とバイナリログの両方で2回の fsync() 呼び出しが発生していました。
一方、InnoDBフォーマットでは、データとバイナリログがInnoDBに統合されたため、innodb_flush_log_at_trx_commit=1 のみを設定すれば安全性が担保されます(Case 2)。
この時のTPSは 5,313 を記録しており、旧フォーマットの安全な設定(Case 8)と比較して約1.86倍(約86%増)という劇的なパフォーマンス向上が確認されました。
また、従来のファイルフォーマットの Case 5は、InnoDB側の耐久性は保証しつつも、バイナリログのディスク同期(fsync())をOS任せにすることでI/O待ちを減らすというパフォーマンスを稼ぐために安全性を一部妥協した設定です。
そのCase 5のTPS 4,190 と比較しても、InnoDBフォーマットのCase 2では 約26.8%(1.26倍)ものパフォーマンス向上 を果たしています。
InnoDBフォーマットの導入によって「パフォーマンスを確保するためにバイナリログの同期(安全性)を犠牲にする」という旧フォーマット時代の苦しい妥協が不要になったということが言えそうです!
2. ディスクI/Oの変化(バッチ化)
また、データ保護を保証する設定(innodb_flush_log_at_trx_commit=1)におけるベンチマークのディスクI/O状況を比較すると、その違いは明白です。
ディスクI/O状況の比較(Case2 vs Case8)
| ケース | binlog_storage_engine | sync_binlog | innodb_flush_log_at_trx_commit | 書き込み回数(w/s) | 書き込み量(wkB/s) | 1回あたりの書き込み量 |
|---|---|---|---|---|---|---|
| Case2 | innodb (新) | (不要) | 1 | 約 1,300 〜 2,200 | 約 44,000 〜 130,000 | 約 35 〜 70 KB/回 |
| Case8 | file (旧) | 1 | 1 | 約 3,000 〜 4,200 | 約 30,000 〜 65,000 | 約 8 〜 15 KB/回 |
上記における I/O効率の変化のポイントを以下に整理します。
- 従来のファイルフォーマット(Case 8)→ 細かいI/Oが大量発生し非効率
- 書き込み回数:多い(約3,000〜4,200回/秒)
- 1回あたりサイズ:小さい(約8〜15KB)
- InnoDBベースの新フォーマット(Case 2)→ I/Oがまとまり効率化
- 書き込み回数:少ない(約1,300〜2,200回/秒)
- 1回あたりサイズ:大きい(約35〜70KB)
この違いは、I/Oが「細切れ」から「まとめ書き(バッチ化)」へ変化したことを意味します。
MariaDBには、複数のトランザクションを単一のディスクI/O操作でバイナリログにコミットすることでパフォーマンスを向上させるグループコミットという機能があります。
fsync() が1回になったことでグループコミットが制約なく機能するようになり、より多くのトランザクションを1回のI/Oにまとめて効率的にディスクへ書き込めるようになったことが、このバッチ化の最大の要因だと思います。
結果として、ストレージの帯域をより有効に活用できるようになり、TPSの劇的な向上に繋がりました。
導入前の注意点とトレードオフ
ただし、手放しで導入するのではなく、インフラ要件やチューニングに注意が必要となります。
REDOログの増幅
InnoDBフォーマットの導入において、パフォーマンスの向上と引き換えに発生する最も重要なトレードオフが「REDOログの増幅」です。
InnoDBフォーマットでは、バイナリログのイベントが独立したファイルではなく、InnoDBのテーブルスペース(.ibbファイル)内に統合して保存されます。
このアーキテクチャの変更により、すべてのバイナリログイベントがInnoDBのREDOログとしても二重に記録されるため、本検証環境では REDOログが従来のファイルフォーマットと比較して約2倍増加 しました。
REDOログ発生量の比較
| innodb_flush_log_at_trx_commit | Case | binlog_storage_engine | REDOログ発生量 |
|---|---|---|---|
| 0 | Case 1 | innodb (新) | 約 26.47 GB |
| 0 | Case 4 | file (旧) | 約 13.60 GB |
| 1 | Case 2 | innodb (新) | 約 22.37 GB |
| 1 | Case 5 | file (旧) | 約 10.50 GB |
| 2 | Case 3 | innodb (新) | 約 26.84 GB |
| 2 | Case 6 | file (旧) | 約 13.99 GB |
検証結果を同一の耐久性設定(innodb_flush_log_at_trx_commit)で比較した場合、InnoDBフォーマットは約2倍程度のRedoログ増加を確認できます。
小さなトランザクションが中心のOLTPワークロードではこの影響は軽微ですが、大量のデータ更新を伴う処理では無視できないオーバーヘッドとなります。
ちなみにですが、 innodb_flush_log_at_trx_commit=1 と そうでないとき( 0 or 2 )ときでREDOログの発生量が異なる大きな要因としては「TPS/QPS」の差が原因だと考えられます。
innodb_flush_log_at_trx_commit=1 は、トランザクションコミットごとにREDOログへのディスク同期が走るため、設定値の中では最もパフォーマンスが悪くなります。
例えば、 Case1(innodb_flush_log_at_trx_commit=0) と Case2(innodb_flush_log_at_trx_commit=1) では、TPS/QPSは 約1.3倍の差、REDOログ発生量は約1.2倍ほどの差となり、処理量とREDOログ量がある程度同期しています。
処理量が低下すれば、その分発生するREDOログ量にも差がつくことになるので、このような結果になったと言えそうです。
innodb_log_file_size の拡張設定が必須
このREDOログの大幅な増幅に伴い、運用設計において極めて重要な変更点があります。
それは innodb_log_file_sizeの再設定 です。
REDOログの消費ペースが増加するため、大量のINSERTやUPDATEなどのバッチ処理を行った際、ログファイルサイズが小さすぎると古いログレコードが急激に上書きされてしまいます。
その結果、万が一のシステムクラッシュ時に、リカバリに必要なデータが不足してしまい「クラッシュリカバリに失敗する」という致命的なリスク(MDEV-38462の既知の不具合)が高まります。
この深刻な事態を防ぐために、InnoDBフォーマットを本番環境に導入する際は、innodb_log_file_size を従来の2倍程度(例えば2GBで運用していた場合は4GBなど)に余裕を持って拡張設定することが強く推奨されます。
事前のサイジングにおいて、このREDOログ増幅を前提としたストレージの容量・帯域設計を行うことが、新フォーマットを安全に運用する鍵となります。
ストレージのディスク帯域の枯渇リスク
また、fsync() の待ち時間がなくなる分、ディスクへの書き込み量が急増するため、ストレージのI/O帯域が新たなボトルネックになる可能性があります。
同じ条件で、ストレージのI/O帯域を最大スループット 54 MB/秒(6,750 IOPS)に設定しベンチマークを実施したところ、I/O帯域がボトルネックになり、従来のファイルフォーマット(Case 4〜9)よりもTPSが20%以上低下し、全ケースの中で最もパフォーマンスが悪化する という結果になりました。
| ケース | binlog_storage_engine | sync_binlog | innodb_flush_log_at_trx_commit | TPS | QPS |
|---|---|---|---|---|---|
| Case 1 | innodb(新) | 0 | 0 | 776 ★ | 4661 |
| Case 2 | innodb(新) | 0 | 1 | 770 ★ | 4625 |
| Case 3 | innodb(新) | 0 | 2 | 756 ★ | 4537 |
| Case 4 | file(旧) | 0 | 0 | 1018 | 6108 |
| Case 5 | file(旧) | 0 | 1 | 977 | 5867 |
| Case 6 | file(旧) | 0 | 2 | 1013 | 6078 |
| Case 7 | file(旧) | 1 | 0 | 985 | 5914 |
| Case 8 | file(旧) | 1 | 1 | 925 | 5552 |
| Case 9 | file(旧) | 1 | 2 | 977 | 5862 |
従来のファイルフォーマット(Case 4など)では、1トランザクションあたりのデータ量が軽いため、この帯域幅でも1,000 TPS以上の処理をこなす余裕がありました。
しかし、InnoDBフォーマット(Case 1〜3)は書き込み量が増加するため、750 TPS前後に達した時点でストレージの帯域幅の天井に到達し、その結果、ディスク使用率(%util)が常に100%に張り付く「パンク状態」に陥り、激しいデータ転送待ちが発生しました。
本来の強みである「fsync()削減による高速化」の恩恵を受ける前に、物理的なI/O帯域の限界に阻まれてしまったため、パフォーマンスが最も低くなるという結果を招きました。
この検証から、新フォーマットの性能を最大限に引き出すためには、単に設定を変更するだけでなく、ストレージの帯域幅自体が使い切られることがないか確認することが不可欠であることがわかります。
制限事項およびサポートされていない機能
現時点(MariaDB 12.3.1)のInnoDBフォーマットは Galera Clusterには対応していないこと、準同期レプリケーションがサポートとされていないなどのいくつか注意点があります。
環境によっては、そもそも導入できないということもありえるので、詳細は公式ドキュメントをご確認ください。
まとめ
今回、検証してみてInnoDBベースのバイナリログフォーマットは単なるパラメータチューニングではなく「コミットパイプラインの再設計」であり、MariaDBの大きな進化であると感じました。
これまでデータベース管理者は、「パフォーマンスを稼ぐためにバイナリログの安全性を一部妥協する」か、「安全性を重視してパフォーマンス低下を受け入れる」かの苦しい二者択一を迫られてきました。
MariaDB 12.3のInnoDBフォーマットは、適切なストレージサイジングさえ行えば、この長年の課題を見事に解決してくれます。
特に、高いデータ保護要件と高速な書き込み性能の両立が求められるシステムにおいて、この機能はこれからのMariaDB運用の新たなスタンダードになっていくと思われます。
サポートされていない機能などがまだありますが、今後の対応に期待が高まります。
皆さんもぜひ、検証してみてください!


