はじめに
稼働中のサービスで、急遽インデックスを追加しなければならない場面。
「サービスは止められない。でも ALGORITHM=INPLACE, LOCK=NONE オプションをつければ、参照も更新も止めずに無停止でいける。余裕だ」
そう確信してEnterキーを押した数分後——
Readerで実行中のクエリが次々とKillされて...🚨
これがAurora MySQLの現実です。
この記事では、「Online DDLは安全」という思い込みを打ち砕くAuroraの無慈悲な挙動 と、Aurora MySQL 3に潜むバージョン地雷 について解説します。
※なお、本記事は技術仕様の調査結果をまとめたものです。
📌 この記事で分かること(TL;DR)
- 「LOCK=NONE」は万能ではない。 最初と最後には必ずロックを取る。
- Auroraは「無慈悲」。 DDLを通すために、ReaderのSELECTを問答無用でKillしてくる。
- RDSなら大丈夫? いや、長時間クエリがあればレプリケーション遅延が発生する(でもKillはされない)。
- Aurora v3は「地雷原」。 古いバージョンだとReaderごとクラッシュする(v3.06.1以上へ急げ)。
1. 「LOCK=NONE」という言葉の罠
まず、大前提の誤解を解きましょう。
LOCK=NONE は「ロックを一切取らない」という意味ではありません。
正しくは 実行中(Phase 2)はロックしないけど、最初と最後(Phase 1, 3)はガッツリ排他ロック(メタデータロック:MDL)を取るよ です。
| フェーズ | やってること | ロックの状態 | 影響 |
|---|---|---|---|
| Phase 1: 開始 | 準備体操(初期化) | 排他ロック (一瞬) | ⚠️ 待たされる |
| Phase 2: 実行 | インデックス構築 | ロックなし | ✅ 平和 |
| Phase 3: 終了 | 定義切り替え | 排他ロック (一瞬) | ⚠️ 待たされる |
「一瞬ならいいじゃん?」と思いましたか?
もしその一瞬のタイミングで、Writer上で重い集計クエリ(SELECT)が走っていたら……?
DDLは「ロックが取れない!」と待機状態(Waiting for table metadata lock)に入ります。
ここからが地獄です。
DDLが待機キューに入ると、その後に来た軽いUPDATE/INSERTも巻き添えにして全て待たされ、全てのクエリが詰まります(パイルアップ)。
ちなみに、通常のロック(排他制御)では、UPDATE/INSERTは止まってもSELECTは読み取れます。しかしメタデータロック(MDL)は特殊で、テーブル定義を触る以上、SELECTも含めた全てのアクセスをブロックします。
ReaderのSELECTを殺すだけでなく、Writer自身も「重いSELECT」が一本あるだけで、後続の軽い更新クエリが全て詰まってサービス停止(Too many connections)に追い込まれます。
たった一つのDDLが、サービス全停止を招く瞬間です。
2. なぜAuroraは容赦なくKillするのか?
同じMySQL 8.0エンジンなのに、AuroraだけがReaderのクエリをKillします。
その理由はストレージを共有しているからです。
🏡 Aurora:ストレージ共有の代償
WriterとReaderが同じストレージ(部屋) を見ている。
- Writer: 「よし、今すぐテーブル構造を変更(DDL)するぞ!」
- Reader: 「ちょ、今そのテーブルでSELECT中なんだけど!?」
- Writer: 「知らん。どけ(Kill)」
もう少し技術的に言うと、メタデータキャッシュの不整合を防ぐためです。
Writerでテーブル定義が変わった瞬間、Readerが古い定義(キャッシュ)を持ったままだとデータが壊れてしまいます。そのため、WriterはDDL完了時に全Readerへ「キャッシュを捨てろ」と命令し、それを掴んでいるクエリがいれば強制排除(Kill)するのです。
これは共有ストレージ型アーキテクチャの宿命と言えます。
📝 参考:RDSはなぜKillしないのか?
RDSは独立したストレージを持っています。
DDLは「Writerで完了」→「バイナリログ転送」→「Readerで再実行」という流れ。
時間軸がズレているので、Readerは「今SELECT中だから、DDL適用は後で」と待てます。
ただし、長時間SELECTがあるとレプリケーション遅延が発生します。
3. 地獄のシナリオ:Readerで分析クエリ実行中にDDLを打つと?
では、Readerで重いSELECTを実行中に、WriterでDDLを打つとどうなるか。
💀 Auroraの惨劇
WriterでDDLを開始(Phase 1)または終了(Phase 3)した瞬間、Readerで実行中のクエリが問答無用でKillされます。
クエリの長短は関係ありません。0.1秒のSELECTも、30分の集計クエリも、平等に殺されます。
📊 シナリオ別:Auroraでの生存確率
| シナリオ | DDLタイミング | Aurora MySQL |
|---|---|---|
| WriterでSELECT中、DDLを開始 | Phase 1 開始 | ⚠️ 待機(Pile-up) |
| WriterでSELECT中、DDL実行中 | Phase 2 実行 | ✅ 安全 |
| WriterでSELECT中、DDLが終了 | Phase 3 終了 | ⚠️ 待機(Pile-up) |
| ReaderでSELECT中、DDLを開始 | Phase 1 開始 | 💀 Kill(強制終了) |
| ReaderでSELECT中、DDL実行中 | Phase 2 実行 | ✅ 安全 |
| ReaderでSELECT中、DDLが終了 | Phase 3 終了 | 💀 Kill(強制終了) |
重要:
- Writer上のクエリ:メタデータロック(MDL)待ちが発生(RDSと同じ)
- Reader上のクエリ:Phase 1とPhase 3で問答無用Kill
🆚 RDSならどうなる?(参考)
| RDS MySQL | 説明 |
|---|---|
| ✅ Killはされない | Readerは独立したストレージなので、DDL開始時は無関係 |
| ⚠️ 長時間SELECT中だと遅延 | DDL終了時、Readerで長時間SELECTがあればレプリケーションが待機 (SELECT終了までラグが発生) |
RDSは優しい(Killしない)が、長時間クエリがあるとレプリケーション遅延という別の問題が発生します。
✅ Phase 2(DDL実行中)は安全地帯
インデックス構築中(Phase 2)は、RDSもAuroraも問題なくSELECTできます。これがLOCK=NONEの本来の恩恵です。
4. 🚨 Aurora MySQL 3 ユーザーへの警告
ここまでの話は「仕様」ですが、ここからはバージョンの罠の話です。
もし Aurora MySQL 3 (v3.06未満) を使っているなら、今すぐバージョンを確認してください。
💣 Readerが「クエリ失敗」どころか「クラッシュ」する
初期〜中期のAurora MySQL 3では、Online DDL周りに深刻なバグがありました。
-
v3.04.2以前: DDL実行中にReaderを見ると、
ERROR 1146: Table does not exist(テーブル消滅!?) と言われる - v3.04.3以前: DDL実行中にReaderを見ると、Readerインスタンスが再起動(クラッシュ) する
「クエリがKillされる」ならリトライで済みますが、「インスタンス再起動」は障害です。
🗺️ Aurora MySQL 3 バージョン別「地雷マップ」
| バージョン | 状態 | 主な問題 |
|---|---|---|
| 3.01〜3.04.1 | 💣💣💣 超危険 | Writer DDL中にReaderクラッシュ多発 |
| 3.04.2〜3.04.3 | 💣💣 危険 | 一部改善も問題残存 |
| 3.04.4以降 | ⚠️ 要注意 | 「Table does not exist」修正 |
| 3.06.1以降 | ✅ 推奨 | ALTER中のReader再起動を修正 |
| 3.08.x | ✅ 最推奨 | エッジケース対策完了 |
⚠️ v3.04系を使っている方へ: 今すぐAWSコンソールでバージョンを確認し、メンテナンスウィンドウでのアップグレード計画を立ててください。本番DDLはその後です。
✅ 生存ラインは「v3.06.1」以上
AWSのリリースノートを確認すると、これらの致命的なバグは以下のバージョンで修正されています。
- Aurora MySQL 3.06.1: ALTER中のReader再起動問題を修正
- Aurora MySQL 3.04.4: 「Table does not exist」問題を完全修正
結論:本番でDDL打つなら、v3.06.1以上(できれば最新のv3.08系)に上げてからにしましょう。
5. オンラインDDL実行時の注意点
オンラインDDL実行時の推奨設定
-
lock_wait_timeoutを短く設定DDL実行前に、DDLセッションで設定しましょう。
SET SESSION lock_wait_timeout = 60; -- 60秒でタイムアウトデフォルトは31,536,000秒(1年!!)なので、設定しないとメタデータロック待ちで永遠に待ち続けます。
-
innodb_online_alter_log_max_sizeの調整更新頻度が高いテーブルの場合、DDL中のDML変更を記録するログサイズ上限を増やす:
-- パラメータグループで設定(要再起動) innodb_online_alter_log_max_size = 1073741824 -- 1GB(デフォルト128MB)注意: この領域が溢れると、DDLはエラー終了(ロールバック)します。「3時間待った挙句にエラー」という悲劇を防ぐため、更新が多いテーブルでは十分大きく(1GB〜)取っておきましょう。
-
実行タイミングの選定(超重要)
「Online DDLだからいつでも流せる」は大間違いです。 可能な限りオフピークタイム(閑散期)を狙いましょう。
-
更新が多いとDDLが失敗する: DDL中の変更ログ(
innodb_online_alter_log)が溢れると、数時間かけたDDLがロールバックします - ロックが取れずに詰まる: 実行中のクエリが途切れないと、Phase 1/3の排他ロックが取れず、パイルアップやReader Killが発生します
- 負荷でサービスが重くなる: インデックス構築はCPU/IOを大量に消費するため、ピーク時に実行すると応答速度が低下します
理想は閑散期の深夜帯です。ブルーグリーンデプロイなども待てず、緊急対応でピーク時に実行せざるを得ない場合は、上記のリスクを理解した上で覚悟を決めて実行しましょう。 モニタリングは必須です。
-
更新が多いとDDLが失敗する: DDL中の変更ログ(
まとめ
-
LOCK=NONEを過信するな。 Phase 1と3では排他ロックが必要 -
RDSとAuroraでは挙動が真逆。 アーキテクチャの違いを理解してDDLを実行する
- RDS:レプリケーション遅延が発生(Readerは待ってくれる)
- Aurora:Readerのクエリが強制終了(Writerが優先される)
- Aurora MySQL 3 のバージョンは命綱。 v3.06.1未満では致命的なバグがある
最後に一言。
「LOCK=NONE だからヨシ!」と安易に指差し確認する前に、この記事を思い出してください。
Auroraは優しくありません。でも、理解すれば怖くない(はず)。
参考文献
Amazon Aurora / RDS の仕様と挙動
- Impact of DDL Operations on Aurora MySQL Readers - Percona Blog
- Amazon Aurora レプリカ では metadata lock 待ちが発生しない
- MySQLでオンラインでDDLを実行する際の注意点について
- Aurora 3.04.2 での DDL の予期しない挙動 - freee Developers Hub
MySQL 8.0 公式ドキュメント
- Online DDL Operations - 日本語翻訳が間違っているので英語を見たほうが良い
- Online DDL Performance and Concurrency
AWS 公式
- Amazon Aurora MySQL でのレプリケーション
- Aurora MySQL 3.04.4 リリースノート - 「Table does not exist」修正
- Aurora MySQL 3.06.1 リリースノート - Reader再起動修正