0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「LOCK=NONEだからヨシ!」と指差し確認したリーダーがAuroraにKillされるまで

Posted at

はじめに

稼働中のサービスで、急遽インデックスを追加しなければならない場面。

「サービスは止められない。でも ALGORITHM=INPLACE, LOCK=NONE オプションをつければ、参照も更新も止めずに無停止でいける。余裕だ

そう確信してEnterキーを押した数分後——

Readerで実行中のクエリが次々とKillされて...🚨

これがAurora MySQLの現実です。

この記事では、「Online DDLは安全」という思い込みを打ち砕くAuroraの無慈悲な挙動 と、Aurora MySQL 3に潜むバージョン地雷 について解説します。

※なお、本記事は技術仕様の調査結果をまとめたものです。

📌 この記事で分かること(TL;DR)

  1. 「LOCK=NONE」は万能ではない。 最初と最後には必ずロックを取る。
  2. Auroraは「無慈悲」。 DDLを通すために、ReaderのSELECTを問答無用でKillしてくる。
  3. RDSなら大丈夫? いや、長時間クエリがあればレプリケーション遅延が発生する(でもKillはされない)。
  4. 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実行時の推奨設定

  1. lock_wait_timeoutを短く設定

    DDL実行前に、DDLセッションで設定しましょう。

    SET SESSION lock_wait_timeout = 60;  -- 60秒でタイムアウト
    

    デフォルトは31,536,000秒(1年!!)なので、設定しないとメタデータロック待ちで永遠に待ち続けます。

  2. innodb_online_alter_log_max_sizeの調整

    更新頻度が高いテーブルの場合、DDL中のDML変更を記録するログサイズ上限を増やす:

    -- パラメータグループで設定(要再起動)
    innodb_online_alter_log_max_size = 1073741824  -- 1GB(デフォルト128MB)
    

    注意: この領域が溢れると、DDLはエラー終了(ロールバック)します。「3時間待った挙句にエラー」という悲劇を防ぐため、更新が多いテーブルでは十分大きく(1GB〜)取っておきましょう。

  3. 実行タイミングの選定(超重要)

    「Online DDLだからいつでも流せる」は大間違いです。 可能な限りオフピークタイム(閑散期)を狙いましょう。

    • 更新が多いとDDLが失敗する: DDL中の変更ログ(innodb_online_alter_log)が溢れると、数時間かけたDDLがロールバックします
    • ロックが取れずに詰まる: 実行中のクエリが途切れないと、Phase 1/3の排他ロックが取れず、パイルアップやReader Killが発生します
    • 負荷でサービスが重くなる: インデックス構築はCPU/IOを大量に消費するため、ピーク時に実行すると応答速度が低下します

    理想は閑散期の深夜帯です。ブルーグリーンデプロイなども待てず、緊急対応でピーク時に実行せざるを得ない場合は、上記のリスクを理解した上で覚悟を決めて実行しましょう。 モニタリングは必須です。


まとめ

  • 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 の仕様と挙動

MySQL 8.0 公式ドキュメント

AWS 公式

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?