このサイトのコンテンツは、人工知能(AI)または機械翻訳技術を使用して翻訳されており、誤りが含まれている場合があります。

Skip to content

Roblox、サービス再開

10月28日から始まり、10月31日に完全に復旧するまで、Robloxでは73時間に及ぶサービス停止が発生しました¹。毎日5,000万人のプレイヤーがRobloxを利用しており、プレイヤーが期待する体験を提供するために、当社では数百もの内部オンラインサービスを活用しています。大規模なサービスでは時折サービス中断が発生しますが、今回の停止は期間が長かったため、特に注目すべき事象となりました。 このサービス停止について、コミュニティの皆様に心よりお詫び申し上げます。

今回の技術的な詳細を共有することで、問題の根本原因、その対処方法、そして将来同様の問題が発生しないようにするために当社が取り組んでいることを、コミュニティの皆様にご理解いただきたいと思います。なお、本件においてユーザーデータの損失や、第三者による情報への不正アクセスは一切なかったことを改めてお伝えします。

RobloxのエンジニアリングチームとHashiCorpの技術スタッフが協力し、Robloxのサービス復旧に尽力しました。膨大なリソースを提供し、問題が解決するまで休むことなく共に取り組んでくれたHashiCorpチームに、心より感謝申し上げます。

サービス停止の概要

今回のサービス停止は、その継続時間と複雑さの両面で特異なものでした。チームは根本原因を特定し、サービスを復旧させるために、一連の課題に順次対処する必要がありました。

  • サービス停止は73時間に及びました。
  • 根本原因は 2 つの問題に起因していました。Consul 上で比較的新しいストリーミング機能を有効にした際、異常に高い読み取りおよび書き込み負荷がかかったことで、過度な競合が発生し、パフォーマンスが低下しました。さらに、当社の特定の負荷条件が、BoltDB において病的なパフォーマンスの問題を引き起こしました。オープンソースの BoltDB システムは、Consul 内でリーダー選出およびデータレプリケーションのための書き込み先行ログ(WAL)を管理するために使用されています。 
  • 複数のワークロードをサポートする単一のConsulクラスタが、これらの問題の影響を悪化させました。
  • Consulの実装の深部に潜む、本来は無関係なこれら2つの問題を診断する上での困難が、ダウンタイムの長期化の主な原因となりました。 
  • 障害の原因をより明確に把握できたはずの重要な監視システムは、Consul などの影響を受けたシステムに依存していました。この組み合わせが、トリアージのプロセスを著しく妨げました。
  • Roblox を長期間の完全ダウン状態から復旧させるにあたり、我々は慎重かつ周到なアプローチをとりましたが、それにもかなりの時間を要しました。
  • モニタリングの改善、オブザーバビリティ・スタックにおける循環依存関係の解消、およびブートストラップ・プロセスの高速化に向けたエンジニアリングの取り組みを加速しています。 
  • また、複数のアベイラビリティゾーンおよびデータセンターへの移行も進めています。
  • 今回の事象の根本原因となったConsulの問題については、現在修正を進めています。

はじめに:当社のクラスタ環境とHashiStack

Roblox のコアインフラストラクチャは、Roblox のデータセンターで稼働しています。当社は、自社ハードウェアをデプロイ・管理するとともに、そのハードウェア上で独自のコンピューティング、ストレージ、ネットワークシステムを運用しています。デプロイの規模は極めて大きく、18,000 台以上のサーバーと 170,000 個以上のコンテナを擁しています。

複数のサイトにまたがる数千台のサーバーを運用するため、当社は一般に「HashiStack」として知られる技術スイートを活用しています。NomadConsulVaultは、世界中のサーバーとサービスを管理し、Robloxサービスを支えるコンテナをオーケストレーションするために使用している技術です。

Nomadはジョブのスケジューリングに使用されます。どのコンテナをどのノードで実行するか、またどのポートでアクセス可能にするかを決定します。また、コンテナのヘルスチェックも行います。これらのデータはすべて、IPとポートの組み合わせを管理するデータベースである「サービスレジストリ」に中継されます。Robloxの各サービスは、このサービスレジストリを利用して相互に発見し合い、通信を行います。このプロセスは「サービスディスカバリー」と呼ばれます。 当社は、サービスディスカバリー、ヘルスチェック、セッションロック(その上に構築されたHAシステム向け)、およびKVストアとしてConsulを使用しています。

Consulは、2つの役割を持つマシンのクラスタとしてデプロイされます。「Voters」(5台)はクラスタの状態を権威的に保持し、「Non-voters」(追加の5台)は読み取り専用レプリカとして、読み取りリクエストのスケーリングを支援します。いつでも、Votersのうち1台がクラスタによってリーダーとして選出されます。リーダーは、他のVotersへのデータレプリケーションと、書き込まれたデータが完全にコミットされたかどうかの判定を担当します。  Consulは、リーダー選出およびクラスター内の各ノードが更新内容に合意することを保証する形で状態をクラスター全体に分散させるために、Raftと呼ばれるアルゴリズムを使用しています。1日のうちにリーダー選出を通じてリーダーが数回変更されることは珍しくありません。

以下は、インシデント発生後のRobloxにおけるConsulダッシュボードの最近のスクリーンショットです。このブログ記事で言及されている主要な運用メトリクスの多くは、正常なレベルを示しています。例えば、KV適用時間は300ms未満であれば正常とみなされますが、この時点では30.6msとなっています。Consulリーダーは過去32ms以内にクラスタ内の他のサーバーと通信しており、これはごく最近のことです。

1. Robloxにおけるコンスルの通常業務

10月のインシデントに至るまでの数ヶ月間、Robloxは新しいストリーミング機能を活用するため、Consul 1.9からConsul 1.10へアップグレードしました。このストリーミング機能は、Robloxのような大規模クラスター全体に更新を配信するために必要なCPUリソースとネットワーク帯域幅を大幅に削減するように設計されています。

初期検知(10月28日 13:37)

10月28日の午後、Vaultのパフォーマンスが低下し、1台のConsulサーバーで高いCPU負荷が確認されました。Robloxのエンジニアが調査を開始しました。この時点では、プレイヤーへの影響はありませんでした。

初期対応(10月28日 13:37 – 10月29日 02:00)

初期調査の結果、Vaultやその他多くのサービスが依存しているConsulクラスターの状態が正常ではないことが示唆されました。  具体的には、Consulクラスタのメトリクスにおいて、Consulがデータを格納する基盤となるKVストアの書き込みレイテンシが上昇していることが確認されました。これらの操作における50パーセンタイルのレイテンシは通常300ms未満でしたが、この時は2秒に達していました。Robloxの規模ではハードウェアの問題は珍しくなく、Consulはハードウェア障害を乗り越えることができます。しかし、ハードウェアが故障しているのではなく単に動作が遅い場合、Consul全体のパフォーマンスに影響を及ぼす可能性があります。 このケースでは、チームはハードウェア性能の低下を根本原因と疑い、Consulクラスタのノードの1つを交換する作業を開始しました。これが、このインシデントに対する最初の診断試みでしたこの頃、HashiCorpのスタッフがRobloxのエンジニアに加わり、診断と復旧を支援しました。以降、「チーム」および「エンジニアリングチーム」という表現は、RobloxとHashiCorpの両方のスタッフを指します。

新しいハードウェアを導入したにもかかわらず、Consulクラスタのパフォーマンスは依然として低下したままでした。16時35分には、オンラインプレイヤー数が通常の50%まで減少しました。

2. 太平洋標準時 16:35 のプレイヤー・ドロップ中の CCU

今回のダウンは、システムの健全性が著しく低下した時期と重なり、最終的にはシステム全体の停止につながりました。その理由は?Robloxのサービスが別のサービスと通信しようとする際、通信先のサービスの位置情報を最新の状態に保つためにConsulに依存しています。 しかし、Consulが正常に動作していないと、サーバーは接続に苦労します。さらに、NomadとVaultもConsulに依存しているため、Consulが正常でない場合、システムは新しいコンテナのスケジューリングや、認証に使用される本番環境のシークレットの取得ができなくなります。要するに、Consulが単一障害点であり、かつ正常に動作していなかったためにシステムがダウンしたのです。

この時点で、チームは問題の原因について新たな仮説を立てました。それは、トラフィックの増加です。システムが限界点に達し、Consulが稼働しているサーバーが負荷に耐えきれなくなったために、Consulの応答が遅くなっていたのではないでしょうか?これが、インシデントの根本原因を特定するための2度目の試みでした。

インシデントの深刻さを踏まえ、チームはConsulクラスタ内の全ノードを、より高性能な新しいマシンに置き換えることを決定しました。これらの新しいマシンは128コア(2倍の増強)を搭載し、より新しく高速なNVMe SSDディスクを採用していました。19:00までに、チームはクラスタの大部分を新しいマシンへ移行しましたが、クラスタの状態は依然として正常ではありませんでした。 クラスタの報告によると、ノードの大半が書き込み処理に追いついておらず、KV書き込みの50パーセンタイルレイテンシは、通常の300ミリ秒以下ではなく、依然として約2秒のままでした。

サービス復旧の試み #1 (10月29日 02:00 – 04:00)

Consulクラスタを正常な状態に戻すための最初の2回の試みは失敗に終わりました。KV書き込みのレイテンシが高止まりしていることに加え、説明のつかない新たな症状も確認されました。それは、Consulリーダーが他の投票ノードと定期的に同期を失うというものでした。 

チームは、Consulクラスタ全体をシャットダウンし、障害発生の直前の数時間前に取得したスナップショットを使用して状態をリセットすることを決定しました。これにより、システム構成データ(ユーザーデータではない)が多少失われる可能性があることは承知していました。しかし、障害の深刻さと、必要であれば手動でシステム構成データを復元できるという確信から、これは許容範囲内であると判断しました。 

システムが正常な状態で取得したスナップショットから復元すれば、クラスタも正常な状態に戻ると予想していましたが、もう一つ懸念がありました。この時点ではRobloxのシステムを通るユーザー生成トラフィックは一切ありませんでしたが、Robloxの内部サービスは稼働しており、依存関係の場所を確認したり、ヘルス情報を更新したりするために、コンスルに定期的にアクセスしていました。これらの読み書き操作が、クラスタにかなりの負荷をかけていました。 クラスタのリセットが成功したとしても、この負荷によってクラスタが即座に不健全な状態に戻ってしまうのではないかと懸念していました。この懸念に対処するため、クラスタ上で iptables を設定してアクセスをブロックしました。これにより、制御された方法でクラスタを再起動させることができ、ユーザートラフィックとは独立して Consul に課している負荷が問題の一因であるかどうかを把握するのに役立ちました。

リセットは順調に進み、当初はメトリクスも良好に見えました。iptablesによるブロックを解除すると、内部サービスからのサービスディスカバリおよびヘルスチェックの負荷は予想通り戻りました。しかし、Consulのパフォーマンスは再び低下し始め、最終的には元の状態に戻ってしまいました。KV書き込み操作の50パーセンタイルが再び2秒に達したのです。 Consulに依存するサービスが次々と「不健全」と自己判定し始め、やがてシステムは、もはやお馴染みとなった問題のある状態に陥りました。時刻は午前4時でした。Consulへの負荷に何らかの問題を引き起こす要因があることは明らかでしたが、インシデント発生から14時間以上が経過しても、その正体は依然として不明でした。

サービス復旧の試み #2 (10月29日 04:00 – 10月30日 02:00)

ハードウェア障害の可能性は排除していました。高速なハードウェアを導入しても改善は見られず、後に判明したように、かえって安定性を損なう可能性さえありました。Consulの内部状態をリセットしても、状況は変わりませんでした。 ユーザーからのトラフィックは一切入っていなかったにもかかわらず、Consulの動作は依然として遅かった。私たちはiptablesを活用して、トラフィックを徐々にクラスタに戻していた。再接続を試みる数千ものコンテナの膨大な量によって、クラスタが単に不安定な状態に押し戻されていたのだろうか?これが、インシデントの根本原因を特定するための3度目の試みだった

エンジニアリングチームは、Consulの使用を削減し、その後慎重かつ体系的に再導入することを決定しました。クリーンな開始点を確保するため、残りの外部トラフィックもブロックしました。 私たちはConsulを使用するサービスの網羅的なリストを作成し、必須ではないすべての使用を無効にする設定変更を展開しました。対象となるシステムや設定変更の種類が多岐にわたったため、このプロセスには数時間を要しました。通常は数百のインスタンスが稼働していたRobloxのサービスは、一桁台までスケールダウンされました。クラスターに余裕を持たせるため、ヘルスチェックの頻度は60秒から10分へと引き下げられました。 障害発生から24時間以上が経過した10月29日16:00、チームはRobloxを復旧させるための2度目の試みを開始しました。今回も再起動の初期段階は順調に見えましたが、10月30日02:00までに、Consulは再び不健全な状態となりました。今回は、Consulに依存するRobloxサービスからの負荷が大幅に減少していたにもかかわらずです。

この時点で、28日に最初に確認されたパフォーマンス低下の要因は、Consulの全体的な使用状況だけではないことが明らかになりました。この認識に基づき、チームは再び方針を転換しました。Consulに依存するRobloxサービスの視点からConsulを見るのではなく、Consulの内部構造を調査して手がかりを探し始めたのです。

競合の調査 (10月30日 02:00 – 10月30日 12:00)

その後10時間にわたり、エンジニアリングチームはデバッグログとOSレベルのメトリクスを詳細に分析しました。このデータから、ConsulのKV書き込みが長時間ブロックされていることが判明しました。つまり、「競合」が発生していたのです。競合の原因はすぐには明らかではありませんでしたが、障害発生初期にサーバーを64コアから128コアへ移行したことが、問題を悪化させた可能性があると推測されました。 以下のスクリーンショットに示すhtopデータとパフォーマンスデバッグデータを検討した結果、チームは障害発生前に使用していたものと同様の64コアサーバーに戻す価値があると結論付けました。チームはハードウェアの準備を開始しました。Consulのインストール、OS設定の三重チェックを行い、可能な限り詳細にマシンを稼働可能な状態に整えました。 その後、チームはConsulクラスタを64コアサーバーに戻しましたが、この変更は効果をもたらしませんでした。これが、本インシデントの根本原因を特定するための4度目の試みでした。

3. その後、上記のようにパフォーマンスレポートでこれを表示しました。時間の大部分は、ストリーミングサブスクリプションのコードパスを経由したカーネルのスピンロックで消費されていました。
4. HTOP che mostra l'utilizzo della CPU su 128 core.

根本原因を特定(10月30日 12:00 – 10月30日 20:00)

数ヶ月前、当社では一部のサービスにおいて、Consulの新しいストリーミング機能を有効化しました。この機能は、ConsulクラスタのCPU使用率とネットワーク帯域幅を低減することを目的としており、期待通りに動作したため、その後数ヶ月にわたり、より多くのバックエンドサービスで段階的にこの機能を有効化していきました。障害発生の前日である10月27日14:00、トラフィックルーティングを担当するバックエンドサービスでもこの機能を有効化しました。 この展開の一環として、年末に通常見られるトラフィックの増加に備えるため、トラフィックルーティングを担うノード数を50%増強しました。インシデントが発生する前日の1日間は、この構成でストリーミング機能も問題なく動作していたため、当初はパフォーマンスが変化した原因が不明でした。 しかし、Consulサーバーからのパフォーマンスレポートとフレームグラフを分析した結果、ストリーミングのコードパスが競合を引き起こし、CPU使用率の高騰を招いているという証拠が見つかりました。そこで、トラフィックルーティングノードを含むすべてのConsulシステムでストリーミング機能を無効にしました。設定変更の反映は15:51に完了し、その時点でConsulのKV書き込みの50パーセンタイルは300msまで低下しました。ついに突破口が見えたのです。

なぜストリーミングが問題となったのでしょうか? HashiCorpの説明によると、ストリーミングは全体的にはより効率的ですが、その実装ではロングポーリングよりも少ない並行制御要素(Goチャネル)を使用していました。非常に高い負荷下、具体的には非常に高い読み取り負荷と書き込み負荷の両方が同時に発生した場合、ストリーミングの設計上、単一のGoチャネルにかかる競合が激化し、書き込み時のブロッキングを引き起こすため、効率が著しく低下してしまうのです。 この挙動は、コア数の多いサーバーで生じた現象の説明にもなりました。それらのサーバーは、NUMAメモリモデルを採用したデュアルソケットアーキテクチャでした。そのため、このアーキテクチャ下では共有リソースへの競合がさらに悪化していました。ストリーミングを無効にすることで、Consulクラスタの健全性を劇的に改善することができました。

この突破口が開かれたにもかかわらず、まだ危機を脱したわけではありませんでした。Consulが断続的に新しいクラスタリーダーを選出する現象が見られましたが、これは正常な動作でした。しかし一方で、一部のリーダーにおいて、ストリーミングを無効化する前に見られたのと同じレイテンシの問題が発生しており、これは正常ではありませんでした。 リーダーの遅延問題の根本原因を示す明確な手がかりはなく、特定のサーバーがリーダーに選出されない限りクラスターは健全であるという証拠があったため、チームは問題のあるリーダーが選出されたままにならないようにすることで問題を回避するという現実的な判断を下しました。これにより、チームはConsulに依存するRobloxサービスを健全な状態に戻すことに注力できるようになりました。

しかし、リーダーの遅延には一体何が起きていたのでしょうか?インシデント発生中は解明できませんでしたが、HashiCorpのエンジニアが障害発生後の数日間で根本原因を特定しました。 Consulは、Raftログを保存するためにBoltDBという人気のオープンソース永続化ライブラリを使用しています。これはConsul内の現在の状態を保存するためではなく、適用されている操作のローリングログを保存するために使用されます。BoltDBが無限に肥大化するのを防ぐため、Consulは定期的にスナップショットを実行します。スナップショット操作では、Consulの現在の状態をディスクに書き出し、その後BoltDBから最も古いログエントリを削除します。 

しかし、BoltDBの設計上、最も古いログエントリが削除されても、BoltDBがディスク上で使用する領域は決して縮小しません。代わりに、削除されたデータの保存に使用されていたすべてのページ(ファイル内の4KBセグメント)は「空き」としてマークされ、その後の書き込みに再利用されます。 BoltDBは、これらの空きページを「フリーリスト」と呼ばれる構造体で追跡しています。通常、フリーリストの更新にかかる時間は書き込みレイテンシに実質的な影響を与えません。しかし、Robloxのワークロードにより、BoltDBにフリーリストのメンテナンスに多大なコストがかかるという深刻なパフォーマンス上の問題が露呈しました。 

キャッシュサービスの復旧(10月30日 20:00 – 10月31日 05:00)

障害発生から54時間が経過していました。ストリーミングが無効化され、動作の遅いリーダーが選出されたままにならないよう防止するプロセスが導入されたことで、Consulは安定した状態を維持していました。チームはサービス復旧に注力する準備が整っていました。

Robloxはバックエンドに典型的なマイクロサービスパターンを採用しています。 マイクロサービス「スタック」の最下層には、データベースとキャッシュがあります。これらのデータベースは障害の影響を受けませんでしたが、通常稼働時には複数のレイヤーにわたって毎秒10億件のリクエストを処理するキャッシュシステムは、正常な状態ではありませんでした。当社のキャッシュは、基盤となるデータベースから容易に再取得できる一時的なデータを格納しているため、キャッシュシステムを正常な状態に戻す最も簡単な方法は、再デプロイすることでした。

キャッシュの再デプロイプロセスでは、一連の問題が発生しました: 

  1. おそらく、以前に実行されたConsulクラスタのスナップショットリセットが原因で、キャッシュシステムがConsul KVに保存している内部スケジューリングデータが不正な状態になっていました。 
  2. 小規模なキャッシュのデプロイには予想以上に時間がかかり、大規模なキャッシュのデプロイは完了しませんでした。調査の結果、ジョブスケジューラが「正常でない」状態ではなく「完全に稼働中」と認識していたノードが存在することが判明しました。これにより、ジョブスケジューラはこのノードに対してキャッシュジョブを積極的にスケジューリングしようとしましたが、ノードが正常でない状態であったため失敗しました。 
  3. キャッシュシステムの自動デプロイメントツールは、大規模なトラフィックを既に処理している大規模デプロイメントに対する段階的な調整をサポートするために構築されたものであり、大規模なクラスタをゼロから立ち上げるための反復的な試行を想定したものではありませんでした。 

チームは徹夜でこれらの問題を特定・解決し、キャッシュシステムが適切にデプロイされていることを確認し、正常性を検証しました。障害発生から61時間後の10月31日05:00、Consulクラスタとキャッシュシステムは正常な状態に戻りました。これでRobloxの残りの部分を起動する準備が整いました。

プレイヤーの復帰(10月31日 05:00 – 10月31日 16:00)

最終的なサービス復旧フェーズは、31日05:00に正式に開始されました。キャッシュシステムと同様に、稼働中のサービスの大部分は、初期の障害発生時またはトラブルシューティングの段階で停止されていました。チームは、これらのサービスを適切な容量レベルで再起動し、正常に機能していることを確認する必要がありました。この作業は順調に進み、10:00までにはプレイヤーへのサービス再開準備が整いました。

キャッシュが冷えた状態であり、システムの挙動もまだ不確実な状況下では、システムを再び不安定な状態に陥らせる可能性のあるトラフィックの急増は避けたいと考えました。トラフィックの急増を防ぐため、DNSステアリングを使用してRobloxにアクセスできるプレイヤーの数を制御しました。これにより、ランダムに選ばれた一定割合のプレイヤーのみをゲーム内に受け入れ、それ以外のプレイヤーは引き続き静的なメンテナンスページへリダイレクトされるようにしました。 割合を増やすたびに、データベースの負荷、キャッシュのパフォーマンス、そしてシステム全体の安定性を確認しました。作業は一日中続き、アクセス数を約10%ずつ段階的に増やしていきました。 熱心なプレイヤーの一部が、私たちのDNSステアリングの仕組みを見抜き、サービス復旧時に「早期」アクセスを得るためにTwitterで情報を共有し始めた様子を見るのは、私たちにとっても嬉しいことでした。障害発生から73時間後の日曜日16時45分、全プレイヤーへのアクセスが許可され、Robloxは完全に稼働しました。

障害を受けてのさらなる分析と変更

10月31日にプレイヤーのRobloxへの復帰が許可されたものの、RobloxとHashiCorpはその後1週間を通じて、本障害に関する理解を深め続けました。 新しいストリーミングプロトコルにおける具体的な競合問題が特定され、その原因が特定されました。HashiCorpはRobloxの利用状況と同規模でのストリーミングベンチマークを実施していましたが、膨大な数のストリームと高い解約率の両方が組み合わさって生じるこの特定の挙動は、これまで観察されたことがありませんでした。 HashiCorpのエンジニアリングチームは、この特定の競合問題を再現するための新しい実験室ベンチマークを作成し、追加のスケールテストを実施しています。また、HashiCorpは、極端な負荷下での競合を回避し、そのような状況でも安定したパフォーマンスを確保できるよう、ストリーミングシステムの設計改善にも取り組んでいます。 

「スローリーダー」問題のさらなる分析により、Raftデータ書き込みに2秒かかる原因やクラスタの一貫性問題の根本原因も明らかになった。エンジニアたちは、BoltDBの内部動作をより深く理解するために、以下のようなフレイムグラフを分析した。

5. BoltDB フリーリスト操作の分析。
前述の通り、ConsulはRaftログデータの保存にBoltDBという永続化ライブラリを使用しています。今回のインシデント中に発生した特定の使用パターンにより、本来16kBである書き込み操作が、実際にははるかに大きなサイズになっていました。この問題は、以下のスクリーンショットで確認できます:
6. 分析に使用したBoldDBの詳細な統計データ。

前述のコマンドの出力からは、いくつかのことがわかります:

  • この4.2GBのログストアには、実際のデータ(すべてのインデックス内部構造を含む)が489MBしか格納されていません。3.8GBは「空き」スペースです。
  • フリーリストは、100万件近くの空きページIDを含んでいるため、7.8MBとなっています

つまり、ログの追加(バッチ処理後の各Raft書き込み)が行われるたびに、実際に追加される生データが16KB以下であっても、7.8MBの新しいフリーリストもディスクに書き出されていたことになります。 

これらの操作に対するバックプレッシャーも、TCPバッファの満杯を引き起こし、正常でないリーダーでの書き込み時間が2~3秒になる一因となっていました。下の画像は、このインシデント中のTCPゼロウィンドウに関する調査結果を示しています。

7. TCPゼロウィンドウに関する研究。TCP受信側のバッファが満杯になり始めると、受信ウィンドウを縮小することがあります。満杯になると、ウィンドウをゼロに縮小することができ、これによりTCP送信側に対して送信を停止するよう指示します。キャプション

HashiCorpとRobloxは、既存のBoltDBツールセットを使用してデータベースを「圧縮」するプロセスを開発・導入し、パフォーマンスの問題を解決しました。

最近の改善点と今後の取り組み

サービス停止から2.5ヶ月が経過しました。この間、私たちは何に取り組んできたのでしょうか? 私たちはこの期間を活用し、障害から可能な限り多くのことを学び、その知見に基づいてエンジニアリングの優先順位を調整し、システムの堅牢化を積極的に進めてきました。Robloxの価値観の一つに「コミュニティを尊重する」というものがあります。何が起きたかを説明する投稿を早く公開することもできたかもしれませんが、公開する前にシステムの信頼性向上において大きな進展を遂げることは、コミュニティである皆様に対する私たちの責務であると考えました。 

完了した、および現在進行中の信頼性向上の全リストは、本記事の枠では長すぎて詳細になりすぎるため、ここでは主な項目をご紹介します:

テレメトリの改善

当社のテレメトリシステムとConsulの間には循環依存関係が存在していました。そのため、Consulが正常に動作していない場合、何が問題なのかを特定するのに役立つテレメトリデータが得られませんでした。この循環依存関係を解消しました。これにより、当社のテレメトリシステムは、監視対象として設定されたシステムに依存しなくなりました。

テレメトリシステムを拡張し、ConsulおよびBoltDBのパフォーマンスに関する可視性を向上させました。これにより、今回の障害を引き起こした状態にシステムが近づいている兆候が見られた場合、極めて的確なアラートを受信できるようになりました。また、Robloxの各サービスとConsul間のトラフィックパターンに関する可視性を高めるため、テレメトリシステムを拡張しました。システムの動作やパフォーマンスを多層的に把握できるようになったことで、システムのアップグレードやデバッグ作業において、すでに大きな助けとなっています。

複数のアベイラビリティゾーンおよびデータセンターへの拡張

すべてのRobloxバックエンドサービスを単一のConsulクラスター上で稼働させていたため、今回のような障害の影響を受けやすくなっていました。すでに、バックエンドサービスをホストする、地理的に独立した追加のデータセンター向けに、サーバーとネットワーク環境を構築済みです。現在、これらのデータセンター内での複数のアベイラビリティゾーンへの移行を進めており、この取り組みを加速させるため、エンジニアリングのロードマップと人員配置計画に大幅な変更を加えました。

Consulのアップグレードとシャーディング

Robloxは依然として急速に成長しているため、複数のConsulクラスターを導入したとしても、Consulにかかる負荷を低減したいと考えています。各サービスがConsulのKVストアやヘルスチェックをどのように利用しているかを検証し、一部の重要なサービスを専用のクラスターに分割することで、中央のConsulクラスターへの負荷を安全なレベルまで低減しました。

Robloxのコアサービスの一部では、より適切な他のストレージシステムが存在するにもかかわらず、データの保存場所としてConsulのKVストアを直接利用していました。現在、このデータをより適切なストレージシステムへ移行する作業を進めています。移行が完了すれば、Consulへの負荷も軽減される見込みです。

大量の不要なKVデータが存在することが判明しました。この不要なデータを削除したことで、Consulのパフォーマンスが向上しました。

HashiCorpと緊密に連携し、BoltDBに代わる新バージョン「bbolt」を導入する作業を進めています。bboltは、フリーリストが無制限に肥大化するといったBoltDB特有の問題を抱えていません。年末のトラフィックがピークとなる時期の複雑なアップグレードを避けるため、この作業は意図的に新年まで延期しました。現在、アップグレードのテストを行っており、第1四半期中に完了する予定です。

ブートストラップ手順および設定管理の改善

サービス復旧作業は、Robloxサービスに必要なキャッシュのデプロイやウォームアップなど、いくつかの要因により遅延しました。このプロセスをより自動化し、エラーの発生を抑えるため、新しいツールとプロセスを開発しています。特に、キャッシュシステムをゼロから迅速に立ち上げられるよう、キャッシュデプロイの仕組みを再設計しました。現在、その実装を進めています。

また、HashiCorpと協力し、長期間の停止後に大規模なジョブを容易に起動できるようにするNomadの機能強化をいくつか特定しました。これらの機能強化は、今月下旬に予定されている次回のNomadアップグレードの一環として導入される予定です。

マシンの構成変更をより迅速に行える仕組みを開発し、導入しました。

ストリーミングの再導入

当初、ConsulクラスタのCPU使用率とネットワーク帯域幅を低減させる目的でストリーミングを導入しました。当社のワークロード規模での新実装のテストが完了次第、システムへの慎重な再導入を予定しています。

パブリッククラウドに関する注記

このようなサービス停止の直後では、Robloxがパブリッククラウドへの移行を検討し、基盤となるコンピューティング、ストレージ、ネットワークサービスをサードパーティに管理させるべきかという疑問が湧くのは当然です。

Robloxの価値観の一つに「長期的な視点を持つ(Take The Long View)」というものがあり、この価値観は当社の意思決定に大きく影響しています。当社がオンプレミスで基盤インフラを自社構築・管理しているのは、現在の規模において、そしてより重要なことに、プラットフォームの成長に伴い到達すると予測される将来の規模において、それがビジネスとコミュニティを支える最善の方法であると信じているからです。 具体的には、バックエンドおよびネットワークエッジサービス向けに自社データセンターを構築・運用することで、パブリッククラウドと比較してコストを大幅に抑制できています。このコスト削減は、プラットフォーム上のクリエイターへの報酬額に直接反映されます。さらに、自社ハードウェアを保有し、独自のエッジインフラを構築することで、パフォーマンスの変動を最小限に抑え、世界中のプレイヤーのレイテンシーをきめ細かく管理することが可能になります。 パブリッククラウドプロバイダーのデータセンターの近くに必ずしも居住していないプレイヤーの体験にとって、安定したパフォーマンスと低遅延は極めて重要です。

なお、私たちは特定のアプローチに固執しているわけではありません。プレイヤーや開発者にとって最も理にかなっているユースケースでは、パブリッククラウドを活用しています。例えば、バースト容量、DevOpsワークフローの大部分、および社内分析の大部分にはパブリッククラウドを利用しています。 一般的に、パブリッククラウドは、パフォーマンスやレイテンシが極めて重要ではなく、かつ限定的な規模で稼働するアプリケーションにとって有効なツールであると考えています。しかし、パフォーマンスとレイテンシが最も重要なワークロードについては、オンプレミスで独自のインフラを構築・運用することを選択しました。これには時間、費用、人材が必要であることを承知の上での選択ですが、それによってより優れたプラットフォームを構築できると確信しています。これは、当社の「長期的な視点を持つ(Take The Long View)」という価値観と一致しています。

障害発生以降のシステム安定性

Robloxでは通常、12月末にトラフィックの急増が見られます。信頼性向上のための課題はまだまだ残っていますが、12月のトラフィック急増期間中、Robloxでは重大な本番環境のインシデントが1件も発生せず、ConsulとNomadの両方のパフォーマンスと安定性が極めて良好であったことをご報告できることを嬉しく思います。当面の信頼性改善策はすでに成果を上げているようであり、長期プロジェクトが完了するにつれて、さらに良い結果が得られるものと期待しています。

結び

世界中のRobloxコミュニティの皆様のご理解とご支援に心より感謝申し上げます。Robloxの価値観の一つである「責任を持つ(Take Responsibility)」に基づき、今回の事態について全責任を負います。 また、HashiCorpのチームに改めて心からの感謝を申し上げます。彼らのエンジニアは、この未曾有の障害発生当初から支援に駆けつけ、最後まで私たちを見捨てませんでした。障害から2ヶ月が経過した今も、RobloxとHashiCorpのエンジニアは緊密に連携し、同様の障害が二度と起こらないよう、共に全力を尽くしています。

最後に、Robloxが素晴らしい職場である理由を改めて証明してくれた同僚たちに感謝したいと思います。Robloxでは、礼儀正しさと相互尊重を大切にしています。物事が順調な時は礼儀正しく振る舞うのは簡単ですが、真価が問われるのは、困難な状況下で互いをどう扱うかです。 73時間に及ぶサービス停止中、時間が刻々と過ぎ、ストレスが募る中で、誰かが冷静さを失ったり、失礼な発言をしたり、誰の責任なのかと声に出して問いただしたりしても不思議ではありませんでした。しかし、実際にはそのようなことは起こりませんでした。 私たちは互いに支え合い、サービスが正常に戻るまで、24時間体制で一つのチームとして協力し続けました。もちろん、今回のサービス停止やそれがコミュニティに与えた影響を誇りに思うわけではありません。しかし、チーム一丸となってRobloxを復活させたこと、そしてその過程のあらゆる局面で互いに礼儀正しく敬意を持って接し合ったことを、私たちは誇りに思っています

この経験から私たちは多くのことを学び、今後Robloxをより強固で信頼性の高いプラットフォームにするために、これまで以上に尽力してまいります。

改めて感謝申し上げます。 

¹ 本ブログ記事に記載されている日付および時刻はすべて太平洋標準時(PST)です。