InnoDBMySQLsysbenchperformance_schema

InnoDBのスピンロック競合の計測とチューニング

MySQL(InnoDB)のロック競合をperformance_schemaとperfで計測し、スピン待機の有無やパラメータ調整がスループットに与える影響を検証した研究(慶應義塾大学 河野研究室)。

背景・課題

InnoDBのロックは競合すると、まずスピン待機し、それでも空かなければOSにスリープを委ねるという2段階の待機戦略を取る。スピンは短時間の競合なら効率的だが、長引くとCPUサイクルを浪費し、OSのスリープはwake-upに数μsのレイテンシを伴う。Intel Skylake世代はスピン中に使われるPAUSE命令のレイテンシが約140サイクルとBroadwell(約10サイクル)やIce Lake(約50サイクル)より突出して長く、デフォルト設定では1回のスピンだけで約7,000サイクルを消費してしまう。どのロックでスピンを省くとスループットが改善するか、待機パラメータの最適値とその理由を定量的に明らかにすることを目的とした。

手法・アプローチ

performance_schemaでロックごとの待機時間・待機回数を計測し、ボトルネックになっているロックを特定した。待機時間の大きいロックに対して、スピンを行わず即座にOSへ処理を譲る改造版を個別にビルドし、通常のスピン待機との性能差を比較。あわせてperfでCPU使用状況とコンテキストスイッチのフレームグラフを取得し、スピン待機からスリープへ移行する流れをコールスタックレベルで確認した。スピン中に挟むPAUSE命令の回数を制御するパラメータについても複数の値を試し、ロック競合が起きやすい単純なワークロードと、より現実に近いOLTPワークロードの両方で比較した。

実験環境・構成

サーバはPAUSEレイテンシの長いIntel Skylake(8コア)、MySQL 8.4.9、負荷生成にsysbenchを使用した。ロック競合が起きやすい単純なワークロードと、テーブル数・データ量を増やしたより現実的なOLTPワークロードの2パターンで、スレッド数を変えながら計測。各条件は複数回実行し、スループットの変動が収束するまで計測を繰り返した。

結果

デフォルト設定を基準に比較したところ、スピンを省く改造の効果はロックによって分かれた。取得回数は非常に多いが実際にはほとんど競合していないロックではスピンを省くことが有効だった一方、実際に競合が起きているロックではかえってスループットが悪化した(最大で数%の低下)。PAUSE命令の挿入回数を減らす方向にパラメータを調整すると、デフォルト比でスループットが最大で1割以上向上し、レイテンシも改善した。逆に増やすと悪化した。ただし、スレッド数がコア数を大きく超えるような高並列条件では、この傾向が逆転する場合もあった。

考察

ロックごとに結果が分かれた理由は競合の実態の違いにある。取得回数が多くても実際にはほとんど競合していないロックでは、スピン自体が無駄な処理になっており、それを省くことがそのまま効いた。一方、実際に競合が起きているロックでは、スリープへ切り替わるタイミングの粗さがロックの保持時間を大きく上回ってしまい、スピンを省くとかえって遅延が増えたと考えられる。PAUSE命令の挿入回数についても、Skylakeは1回あたりのレイテンシが長いぶんデフォルトの回数では1回のスピンに時間がかかりすぎており、回数を減らすことでロック解放をより早く検知できるようになったと考えられる。一方、スレッド数がコア数を大きく上回る環境では、スピンを減らすとキャッシュライン競合が増えてしまい、逆効果になる場合もあった。また、CPU使用状況の分析からは、実際にスピンが集中している箇所が当初想定していたロックとは異なるケースもあり、狙ったロックへの対策だけでは効果が限定的になることもわかった。

今後の課題

プロファイリングで特定した本当のボトルネックとなっているロックを対象にした改善策の検証、Skylake以外の複数世代のCPUでの同様の実験、ロックごとの競合発生率をより直接的に計測する仕組みの追加が今後の課題。