Timee のプラットフォームエンジニアリングチームの徳富博氏による発表「急成長でぶつかったMySQLの罠とその向き合い方」から、Aurora MySQL 運用で遭遇した 7 つの重要な課題とその対策をまとめます。

サービスの急成長に伴い、小規模では問題にならなかった MySQL の挙動が本番環境で深刻な障害を引き起こすことがあります。この発表では、実際の運用経験に基づいた具体的な対策が共有されています。

1. DDL 実行の落とし穴

DDL(Data Definition Language: テーブル定義の変更操作)には「Online DDL」という仕組みがありますが、DDL 実行中もテーブルへのアクセスがブロックされないわけではありません。実際にはメタデータロック(MDL)が必ず発生します。

  • Aurora のレプリカでは DDL 実行時にコネクションが切断されるため、リトライロジックが必須
  • 外部キー制約を追加する際は foreign_key_checks = 0 を設定すると、COPY アルゴリズムではなく INPLACE アルゴリズム(テーブルの再構築を伴わない方式)が使われ、影響を最小化できる

2. MDL ベースのデッドロック

MDL デッドロックは SHOW ENGINE INNODB STATUS に表示されないため、標準的な監視では検知できません。

  • 外部キーが存在すると、DROP/ALTER 操作時に親テーブルに対して広範な MDL が取得される
  • 対策: DDL 操作の前に外部キー制約を削除する

3. レプリカがライターに影響を与える問題

Aurora ではレプリカとライターがストレージボリュームを共有しています。レプリカ上の長時間クエリが undo ログのクリーンアップを妨げ、ライターのパフォーマンスに影響します。

  • MySQL のデフォルトの分離レベルは REPEATABLE READ だが、分析用クエリには READ COMMITTED を使用することで、リードビューの保持期間を短縮し undo ログの蓄積を抑えられる

4. 同時リクエストによるデッドロック

高トラフィック環境では、確率的に発生する競合が確実に障害を引き起こすようになります。

ギャップロックパターン

ギャップロック(インデックスレコード間の隙間に対するロック)同士は競合しませんが、複数のトランザクションが同時に INSERT を実行すると循環待ちが発生します。

S→X ロックエスカレーション

外部キーによる暗黙の S ロックが、同一トランザクション内での X ロック取得をブロックします。

対策:

  • INSERT IGNORE を使用する
  • 操作順序を見直す(INSERT の前に UPDATE を実行)

5. 意図しないロック範囲の拡大

インデックスのない UPDATE 文はテーブル全体をロックします。また、外部キーにより親テーブルへ S ロックが伝播します。

  • バッチ処理が S ロックを保持し続けると、API からの UPDATE が無期限にブロックされる
  • 対策: 適切なインデックスを作成し、バッチ処理では頻繁に COMMIT する

6. 段階的なスロークエリの悪化

ローンチ時は問題なかったクエリが、データ量 × トラフィック量の増加で徐々にボトルネックになります。

  • Datadog Database Monitoring などの監視ツールを導入し、チーム単位で自律的にクエリ最適化できる体制を構築する

7. バッファプールの枯渇

ワーキングセットが innodb_buffer_pool_size を超えると、ストレージからの繰り返し読み取りが発生し、パフォーマンスが急激に低下します。

  • Buffer Pool Hit Ratio と Read IOPS を監視する
  • インスタンスのスケールアップや未使用インデックスの削除で対応する

まとめ

MySQL の問題に向き合う上で重要なポイント:

  • レイヤーを理解する: サーバー層(MDL)と InnoDB 層(行ロック)では検知方法が異なります
  • 衝突回避を設計に組み込む: 高リクエスト環境では確率的な障害が確実に発生します
  • 継続的な改善サイクル: ポストモーテム → 再現 → 防止策 → 監視の流れを定着させることが重要です

参考