この事例を読むべき理由

ライブスポーツ中継のように、トラフィックが秒単位でゼロから数百万に急増するワークロードでは、スケーリングそのものよりも「スケールアウトが効いていないように見える」状況の方が厄介です。NLBを2台から6台に増やしても500エラーが減らないなら、それはサーバの問題ではなくDNSルーティングポリシーの問題である可能性が高いです。

本記事は、モバイルオブザーバビリティ基盤bitdriftがT20ワールドカップのクリケット中継中に1億2100万台の同時gRPC接続を処理した実例を扱います。ポイントはわずか1つの設定変更でした。コードもアーキテクチャも変更していません。

根拠資料: AWS Architecture Blog — How bitdrift scaled to 121 million concurrent gRPC connections

本記事を読み終えると、以下を判断できるようになります。

  • 自サービスのDNSルーティングポリシーがpersistent connection環境でボトルネックになり得るか
  • CloudFront + 複数NLB構成でなぜスケールアウトが無効化されるのか
  • Multi-Value Answerルーティングへ切り替える際の実務チェックリスト

CloudFront edge nodes distributing gRPC connections across multiple NLB origins via Route 53 multi-value routing Technical Structure Concept

問題の本質: Weightedルーティングは「1クエリにつきIP1つ」しか返さない

多くのチームがRoute 53のWeightedルーティングを「負荷分散」と理解しています。しかし実際の挙動は異なります。WeightedルーティングはDNSクエリ1件につきIPを1つしか返しません。重みは「どのIPを引くかの確率」であり、「複数IPを同時に通知する仕組み」ではありません。

これがCloudFront規模で発生すると、次のような連鎖が起きます。

  1. CloudFrontエッジノードがoriginドメインをresolve → IPを1つ取得
  2. そのIPをTTL(60秒)の間キャッシュ
  3. すべてのエッジノードが同じタイミングで同じIPに集中
  4. 該当NLB1台がthundering herdで過負荷
  5. NLBを6台に増やしても、依然としてクエリあたり1IPしか返らないため分散しない

ここで決定的な違いがあります。HTTPはリクエストが短命ですが、gRPCは接続が長命です。接続が確立した瞬間にresolveされたoriginにそのまま居座るため、statelessトラフィックでは「やや偏る程度」で済むDNS設定が、persistent connectionでは致命的な過負荷に増幅されます。

解決策: Multi-Value Answerルーティング

Multi-Value AnswerルーティングはDNSクエリ1件につき最大8個のIPを返し、レコード単位のヘルスチェックを内蔵します。CloudFrontエッジノードは最初のresolve時点から複数originへ接続を分散できます。

# 既存のWeightedレコードを確認
aws route53 list-resource-record-sets \
  --hosted-zone-id Z0123456789ABCDEFGHIJ \
  --query "ResourceRecordSets[?Name=='origin.example.com.']"

# 各NLB用のヘルスチェックを作成 (Multi-Valueではヘルスチェック必須)
aws route53 create-health-check --caller-reference "nlb-1-$(date +%s)" \
  --health-check-config '{
    "Type": "TCP",
    "FullyQualifiedDomainName": "nlb-1-abcdef.elb.us-east-1.amazonaws.com",
    "Port": 443,
    "RequestInterval": 10,
    "FailureThreshold": 3
  }'

# Multi-Value Answerレコードを作成 (IPベースのAレコード、Alias不可)
aws route53 change-resource-record-sets \
  --hosted-zone-id Z0123456789ABCDEFGHIJ \
  --change-batch '{
    "Changes": [{
      "Action": "CREATE",
      "ResourceRecordSet": {
        "Name": "origin.example.com",
        "Type": "A",
        "SetIdentifier": "nlb-1",
        "MultiValueAnswer": true,
        "TTL": 60,
        "ResourceRecords": [{"Value": "203.0.113.10"}],
        "HealthCheckId": "abcdef12-3456-7890-abcd-ef1234567890"
      }
    }]
  }'

必ず守るべき制約

  • Aliasレコードは使用不可。 Multi-Value AnswerはIPベースのAレコードのみ対応します。NLBの各AZにElastic IPを割り当てる必要があります。
  • ALBはこのパターンに使えません。 ALBは固定IPをサポートしていないためです。
  • 同じレコード名にルーティングポリシーを混在させられません。 Multi-Valueレコード検証後に既存のWeightedレコードは削除が必要です。
  • TTLは60秒程度に低く保ってください。フェイルオーバーが高速化します。

切り替え前後の比較は以下の通りです。

項目Before (Weighted)After (Multi-Value)
DNSクエリあたりの返却IP1個最大8個
origin分散TTL期間中は単一NLBに集中初回resolveから複数NLBに分散
急増時の挙動thundering herd、単一NLBが過負荷均等分散、単一障害点なし
ピーク時のエラーCloudFront ↔ NLB間で5xx多発サーバサイドエラー0件
顧客側の変更DNS設定変更のみ

AWS architecture diagram showing Route 53 DNS routing layer between CloudFront and multi-AZ NLB fleet Coding Session Visual

実測データが示すもの

この事例で最も印象的なのは、**「コードもアーキテクチャも変えていない」**という事実です。純粋にRoute 53のルーティングポリシーのみを差し替え、結果は次の通りでした。

指標Before (3/1〜2)After (3/7〜9)改善
ピーク5xxエラー率79.80%0.033%99.96%削減 (約2,418倍)
平均5xxエラー率1.87%0.003%99.84%削減 (約623倍)
サーバサイド障害複数origin失敗0件100%排除
同時接続デバイス (3/8)1億2100万台ゼロエラー処理
ピークRPS563K164Kイベント規模の差

特に注目すべきは、2月27日のイベントで約80%のリクエストがHTTP 500で失敗した点です。3月1日にはNLBを4台に増やしたにもかかわらず問題が再発しました。Weightedルーティングが依然としてIPを1つしか返さなかったため、originを増やす行為自体が無意味だったのです。

この技術の限界と注意点

  • Multi-Valueが万能ではありません。 DNSベースの分散であるため、クライアント側のDNSキャッシュやリゾルバの挙動により実際の分布が偏る可能性があります。
  • ヘルスチェックの遅延に注意。 Request intervalを10秒(Fast)にしても、unhealthy判定まで最低数十秒かかります。瞬間的な障害には依然として脆弱です。
  • Elastic IPの管理負担。 NLBの各AZにEIPを付与する必要があり、IP管理ポリシーが求められます。オートスケーリングとは相性が良くありません。
  • HTTPワークロードでは効果が限定的。 短命なリクエスト-レスポンスパターンでは、従来のWeightedルーティングでも大きな問題にならないことがあります。persistent connection(gRPC、WebSocket)で特に致命的である点を覚えておいてください。
  • 日本のエンタープライズ環境では、事前審査やセキュリティレビューのプロセスにより、障害発生中の緊急DNS変更が難しい場合があります。平時のうちにMulti-Value切り替えを検証しておくのが安全です。

次のステップ学習方向

  1. Route 53のルーティングポリシー4種比較 — Simple、Weighted、Latency、Multi-Value Answer、Failoverの実際の挙動差を検証してみてください。
  2. gRPCロードバランシングの深掘り — クライアントサイドLB(例: gRPCのround_robin)とサーバサイドLBのトレードオフを整理しておくと有用です。
  3. CloudFront originフェイルオーバー設計 — Multi-ValueとOrigin Groupを組み合わせた二重防御戦略を検討してください。

フロントエンド側のスケーリング課題も並行して見ているなら、Interop 2026で注目すべきCSS新機能まとめも参考にしてください。サーバレス/エッジ配信パイプラインを運用中の場合は、Vercel Node.js 20サポート終了マイグレーションガイドも早めに確認しておくと良いでしょう。

Server engineer monitoring 121 million concurrent gRPC connections dashboard with zero error metrics System Abstract Visual

まとめ: スケールアウトが効かない時に疑うべきもの

本件の教訓は明確です。

  1. DNSルーティングポリシーは極限スケールにおいてアーキテクチャ決定と同等に重要です。 WeightedとMulti-Value Answerの差は単なる好みの問題ではありません。
  2. persistent connectionはDNS問題を増幅させます。 HTTPでは無視できる程度の偏りが、gRPC/WebSocketではサービス全体の障害に繋がります。
  3. スケールアウトが効かないなら、まずルーティング層を疑ってください。 NLBを2台から6台に増やしてもエラーが変わらないなら、それはoriginの問題ではありません。
  4. 事前キャパシティレビューを習慣化してください。 ライブイベント中に根本原因を分析するのは地獄です。

もし今CloudFrontの背後に複数NLBを置いてgRPCやWebSocketを配信しているなら、今日すぐにRoute 53コンソールを開いてルーティングポリシーを確認することをお勧めします。設定1行が1億台の接続を支えることも、あるいは崩壊させることもあります。

本コンテンツは、信頼性の高い情報源をもとにAIツールを活用して作成され、編集者によるレビューを経て公開されています。専門家によるアドバイスの代替となるものではありません。