2025/11/01追記:DNSプランが削除された後について説明
AWSと関わるエンジニアになってから、一番濃かった月曜でしたね。
日本の会社なので、US-EAST-1(バージニア北部)リージョンに重いワークロードを積んでいないとはいえ、サポート起票できず、マネコンもままならない状況は、ある種の「非日常」に感じました。
(個人的には、Perplexityがダウンしてたのはかなりの痛手だった)
今回の件に対して、「AWSって、高可用性じゃなかったの?」と疑問に思う人が結構見かけますね。
言いたいことすごくわかります。が、どんな大規模サービスでもゼロから築いてきて今の姿になったので、(わりと心臓部に近いところで)レガシーではあるものの、なかなか手が出せないコンポーネントが存在します。個人的な見立では、今回の障害もそれに帰因できるのでしょう。
ドタバタが落ち着いた今、何が起こったのかを自分なりに理解し、備忘録としてこの記事を残したいと思います。
ネットワーク関連は最低限の知識しか持っておりませんので、変なことを言ったらご指摘いただければ幸いです。
何が起こったの?
障害当日ですでに明らかになったのですが、US-EAST-1リージョンのDynamoDBのエンドポイント解決を担うDNSが急に働かなくなり、空のレコードが返ってしまって、DynamoDBとDynamoDBに依存するサービスがバタバタ倒れていったと一言で片付けます。
もちろんこれだけじゃ物足りないですね。今回の障害を振り返る公式記事が出ましたので、一緒に読んでいきたいと思います。
時間軸
| 日本時間 | 状態 | |
|---|---|---|
| 10/20 15:48 | インシデント発生 | US-EAST-1リージョンサービスへのアクセスエラーと遅延が著しく上昇 |
| 10/20 17:26 | 原因特定中 | US-EAST-1リージョンのDynamoDBの大量エラー並びに他サービスへの影響が確認された |
| 10/20 18:01 | 真因特定 | DynamoDBへのDNS解決が原因であると分かり、修復に着手 |
| 10/20 18:27 | 回復の兆し | 回復が見られ、新規リクエストが成功するように |
| 10/20 19:35 | 初期解決 | バックログ処理が残るが、ほどんとのサービスが復旧完了。EC2インスタンスローンチのエラーがまた確認されている |
| 10/21 07:53 | 完全解決 | すべてのイッシューが解決された |
真因の特定から早期復旧まで思った以上に早かったですね。つまり、外部からの攻撃よりは、オペレーション上のイシューやシステムの不具合が原因だろうと推測できます。
DNSの仕組み・なぜ今回はダメになったか
まず前提として、DynamoDBを含むAWSサービスは、DNSでスケーラビリティを保証しています。裏に隠された膨大な処理キャパシティーをシンプルなエンドポイントでユーザー(社内外)に提供するため、DynamoDBのDNSレコードの更新を扱う内部システムが存在します。このシステムでは、高度な自動化が実装されていて、DNSレコードのアップデートだけでなく、自動復旧やトラブル対応もできて並みの障害じゃ倒れない仕様です。
DNS自動更新システム
このシステムは、大きく二つのコンポーネントで構成されています。
-
DNS Planner
- ロードバランサーのヘルスとキャパシティー状況を監視し、一定時間おきに新しいDNSプランを生成します
- エンドポイント:パブリックリージョンエンドポイント
dynamodb.us-east-1.amazonaws.com以外に、IPv6エンドポイントやアカウント特有のエンドポイントなど、このシステムでDynamoDBの複数エンドポイントを制御している - DNSプラン:全エンドポイントに、どのロードバランサーにどれくらいのウェイトで繋ぐ設定
- 異なるエンドポイント間でリソースの共有をし、耐障害性を高めるように
-
DNS Enactor
- 定期的に新しいDNSプランの有無を確認し、利用可能なプランを取得してRoute 53に適用する
- 三つのAZで完全独立な3台のインスタンスで同じ機能を果たす(ここ大事)
- DNSプランを適用する前に、既存プランと比較して、ちゃんと最新かどうかをチェックすることで適用のゴーサインを出す(ここも大事)
- 適用後に、適用されたプランよりある程度古くなったプランを削除(ガチで大事)
ここまで来て、ジュニアレベルのアーキテクトでも違和感を覚えるのでしょう。同じDNSプランを三台のインスタンスに送って、チェック・適用の操作を三回もさせるのは、さすがに冗長ではありませんか?定期のプルじゃなくイベント駆動のパターンにし、インスタンスの前面にメッセージキューで制御しないのでしょうか?
もちろん言い分はあります。公式の見解に自分なりの解釈を加えてみると:
- 各自インスタンスを完全切り離すのは、高可用性を確保するためだ。それは一理ある。ロードバランサーでも、メッセージキューでも、フェールオーバー処理には時間がかかるので、あえて制御せず、後のこと知らん!の精神でとりあえずイベントを投げれば、確かに一番手っ取り早いかもしれない。あと、かなり低いレイヤーなシステムなので、依存先は少なければ少ないほどよい
- DNSプラン適用プロセスで、状態保存機構(ましてやDynamoDB)を導入したり、ロック機構を作ったりするとかえって複雑性が増し、障害リスクが上昇する。それに、適用プロセスが十分短い時間で完了できる(実際今までできていた)としたら、競合の可能性はかなり低く抑えられる。加えて、Route 53 Transactionで全エンドポイントのレコード更新の原子性を確保すれば、二台のインスタンスが同時に適用操作を行ったとしても、どちらかのプランが適用されるだけの話だ
こうして見れば、案外悪くないソリューションに見えてきたが、実はリスクが潜んでおります。
想定中の競合
まずは想定通りでいきましょう。上記の図通り、稀に二台のEnactorが同時にDNSプランの適用を行うシーンがあります。既存のプランより新しいプランでトリガーされ、ほぼ同時に適用のゴーサインが出されたら、二台が適用のプロセスに入り、バッティングを起こします。競合が起こったエンドポイントでリトライが発生し、リトライが終了したらプラン適用されます。二回適用されるかもしれませんが、両方新しいプランであり、Transactionで原子性が保証されていますので、冗長ではあるが実害はありません。
しかし今回起こってしまったのは、「隠れパターン」の競合です。
「隠れパターン」の競合
一番目に狂った歯車ーー上記の通常の競合において短時間で終わるはずのリトライが、異常に長くなってしまいました(ここは、長いリトライが起こったインスタンスをEnactorAに)。そして、その間で新しいプランが複数生成され、EnactorBでどんどん適用されていきました。EnactorAにおけるリトライが終了した時点で、すでに結構古いプランになったが、適用のゴーサインは最初に出たので、この古いプランは無事適用されました。
ここまで来ても、ただ古いDNSプランが適用されるだけの話ですが、厄介なのは適用後のクリーンアッププロセスです。あいにく、EnactorBのプランがどんどん適用されていたところに、EnactorAの古いプランが上書きしてしまい、それとほぼ同時にEnactorBのクリーンアッププロセスが作動し始めました。そして、上書きの直後にEnactorBのクリーンアッププロセスがEnactorAの古いプラン(現行DNSプラン)を削除すべきと判断し、削除しまいました。結果、Route 53にDynamoDBエンドポイントのDNSレコードがまったく存在しない「真空」 が出来上がってしまいました。最後に、別のEnactor(例えばEnactorC)が新しいDNSプランを適用しようとすると、既存のプランとの比較が出来ず、ゴーサインを出すことすら出来なくなりました。つまり、その「真空」が固定されてしまいました。
以上、件の顛末でした。
直感でもわかると思いますが、やはりなんといってもクリーンアップが怪しいですね。競合が起こってしまい他所のクリーンアッププロセスで既存プランが消滅するのは、想像しやすいパターンです。なので、削除する・しないの判定ロジックは存在するはずです。公式文書によると、「適用したプランより著しく古いプラン」を削除対象とするとありますが、具体的な判定基準は明らかにされていません。最低限、Route 53で利用できるプランが0にならないような制御が入っていれば、あるいは適用ゴーサインの判定を最初だけじゃなく最後にも入れれば、話は別になってたかもしれません。
外部から偉そうに指示厨するのはよくないので、ここまでにしましょう。ソフトウェアアーキテクチャが数えきれない意思決定で形を成し、その波乱万丈を共にしなかったよそ者にとって、分からないものです。
影響サービス
DynamoDB自身は言わずもがな、EC2、NLB、Lambdaなどのコアサービスにも、それぞれ異なる形で影響が波及しました。
EC2
EC2はDropletWorkflow Manager (DWFM) というシステムでインスタンスのローンチを管理しています。DWFMは定期的にDynamoDBを通してステータスチェックを行い、EC2インスタンスの状態変更が正しく行われているのかを掌握しています。
このステータスチェックが出来なくなったところで、既存インスタンスにそこまで影響出なかったが新しいインスタンスをローンチすることが出来なくなりました。
NLB
NLBはほとんどEC2インスタンス上で実行されているので、EC2インスタンスの障害に波及された形です。
Lambda
Lambdaのファンクションメタデータ取得もDynamoDBにかかっています。EC2と似たように、Lambdaも新規作成や更新ができなくなりました。加えて、SQSなどからくるイベントをポーリングするシステムもDynamoDBを使っていますので、イベント処理の遅延が生じました。
などなど、聞いたことのあるサービスはほどんと影響されてしまい、前代未聞(?)レベルの障害でしたね。ここで割愛します。
ポエム
(これは筆者個人の見解であり、所属組織の公式見解を代表するものではありません)
我々は、一方通行の道に進んでるかもしれない。が、それはそれで悪くない
株価に表れたように、今回の件、市場や投資家から意外とポジティブな見方が多かったです。ずっとGCPとAzureにシェア奪われるだの、AI時代に取り残されるだの言われてきたAWSですが、最悪の形でそのとんでもない影響力を示すことになりました。今時のインターネットは、AWSを含む巨大ベンダーなしじゃ回れないことの、最たる例でした。
こんな時にオンプレ回帰など、古き良き時代を取り戻そうとする論調が出てきますが、あえて言い切りましょうーーそれは難しい。そして、戻ったとしてもそんなにいいことはない
巨大ベンダーが運用の責任を取ってくれたのは、実に優れた仕組みだと思います。どんな規模の会社でも高い可用性を持つサービスを構築できるし、DR(災害復旧計画)もポチポチするだけで出来てしまいます。
なにより、責任を薄く広くして社会全体で分担し、個人が気楽になれるという、人間の本性に寄り添うシステムがすでに出来上がっております。ユーザーがSaaS企業と、SaaS企業がAWSと、それぞれの間でSLA/OLAを締結しており、責任をちゃんと転嫁できるスキームになります。その全過程に携わる個人や企業が決められた範疇でしか責任負わなくてよくて、過度なペナルティを課されることもなくなりました。
仮に自社のサーバーでサービスを展開し、今回くらいやらかしがあったら、特定の企業や個人にとっては今以上笑えない事態になっているはずです。自分らの「責任負うキャパシティー」を過大視だけでは問題の解決に繋がらないし、力弱い企業と個人を不幸にするだけです。
開発者として、何ができるの?
もちろん、適切なバックアッププランや高可用性のアーキテクチャ設計など、日ごろからアーキテクト力を高める行動は必要ですが、ぶっちゃけ、究極どうしようもないんじゃないかなと思います。
マルチクラウドにすればいいじゃん!みたいな意見も出てきますが、そこそこうまくいっているITサービスの利益率をもってでも、インフラコストが二倍、三倍になることは到底許容されません。ベンダーを(AWSの他に)分散したところ、分散先の上流にAWSでなにかしらのサービスをホストている可能性もあります。結局、ピラミッドトップの0.01%くらいの可用性に、大金を積んでもよい企業ってどれくらいあるのでしょうか?
それだけじゃありません。AWS/GCP/Azure/他巨大ベンダーetc.を選択することは、毎月そこから領収書をもらうだけではないです。そのベンダーを中心に採用、組織つくり、技術スタックを固めないといけないことになります。同時に、他ベンダーに切り替えることが極めて困難になります。結局、CTOたちが頭抱えて悩む案件ばかりです。
一開発者として、選んだ道を信じて進むしかありませんね。



