メインコンテンツにスキップ
OpenAI

2026年9月11日

エンジニアリング

10 億人超の ChatGPT ユーザーを支えるオンラインストレージの急速な拡張

前例のない成長に対応するため、Python 製アプリケーションストレージ基盤 Habitat を進化させた方法

執筆:技術スタッフ Jon Lee、Chaomin Yu、Ben Ries

読み込んでいます...

ログイン、Codex の設定確認、ChatGPT での新しい会話の開始など、OpenAI のあらゆるプロダクトは、データへ高速かつ確実にアクセスできることを前提としています。こうした各操作では、プロダクトが応答するまでに多数の個別データ参照が必要になる場合があります。それらのリクエストが遅ければ、プロダクトも遅く感じられます。それらのリクエストが失敗すれば、プロダクトは完全に機能しなくなります。

Habitat は、OpenAI のプロダクトが必要な情報へ迅速かつ確実にアクセスできるよう構築したオンラインストレージプラットフォームです。Habitat は現在、約 40 の地域で、週間利用者が 10 億人を超えるプロダクトを支え、毎秒 7,000 万件を超えるリクエストを処理しています。Habitat は、DevDay 2023 で GPTs を支えるために初めて公開され、単一のデータベースに接続するシンプルな Python クライアント側ライブラリとして始まりました。現在では、500 PB を超えるデータを提供する複雑な分散システムです。

図 01 · Habitat とは

オンラインストレージプラットフォーム

Habitat は、OpenAI のプロダクトが必要な情報へ迅速かつ確実にアクセスできるよう構築したオンラインストレージプラットフォームです。

  • リクエスト
  • レスポンス
  • 変更(CDC)

クライアント

オンラインストレージプラットフォーム

ストレージリソース

  • ChatGPT
  • API
  • Codex
  • 内部サービス
  • その他

Habitat

  • キャッシュ処理キャッシュ
  • ACL ポリシー認可
  • 配置とデータレジデンシーデータレジデンシー
  • 暗号化データセキュリティ
  • 分離マルチテナント
  • レート制限リクエストシェーピング
  • ルーティングスキーマ参照 · データレジデンシー
  • Azure Cosmos DBオンラインストレージ
  • Nanobaseオンラインストレージ
  • Valkeyキャッシュ
  • Blob ストレージストレージリソース
CDC サービス変更データキャプチャ
  • Databricks
  • Rockset
  • Kafka
  • その他

この規模のインフラを構築・運用するのは容易ではありませんが、それ自体が並外れて難しいわけでもありません。私たちの状況が特殊だったのは、成熟したプラットフォームを同時に構築しながら、驚異的なユーザー増加とプロダクト需要に対応するため、前例のない速さでスケールする必要があったことです。システムエンジニアは通常、10 倍の規模を想定して構築し、次の 10 倍に備えながら数年間は持ちこたえることを期待します。私たちの場合、過去 3 年間、毎年 10 倍を超える成長を続けてきました。そのため、Habitat の構築と運用は、戦術的な判断と実施順序の積み重ねになりました。各コンポーネントを最低レベルまで理解して既存スタックの性能を限界まで引き出しつつ、ストレージと計算資源の逼迫をしのぎ、基盤への投資に必要な時間を確保してきました。

  • 7,000 万超

    1 秒当たりのリクエスト数

  • 10 億人超

    週間利用者数

  • 500 PB 超

    データ

OpenAI の成長に伴い、Habitat も成長する必要がありました。まずミッションクリティカルなプロダクトトラフィックを任せられる信頼性を確保し、次に世界中のユーザーへ十分な速度を提供し、最後に巨大な規模でも巧みに運用できるようにしました。本稿は、オンラインストレージをスケールした方法を紹介する全 2 部のシリーズ第 1 部です。本稿では、Habitat がどのように進化したか、ライブラリからサービスへ転換した理由、そしてサービス基盤では珍しい言語である Python で書かれたサービスを、信頼性の高いストレージプラットフォーム層へ発展させた方法を紹介します。

今後の記事では、大規模環境でマルチテナントの信頼性を確保した方法、読み取り性能を最適化する多層的な戦略、そして前例のない需要を確実に処理できるよう Azure Cosmos DB との連携を拡大した方法を詳しく紹介します。

Habitat とは

Habitat は、プロダクトエンジニアがデータベース管理を意識しなくて済むようにする、というシンプルな発想から始まりました。Habitat は DevDay 2023 で GPTs を支えるために、ChatGPT のメインサーバーと連携する小規模な Python ライブラリとして初めて公開されました。内部ではデータベースアプリケーションの Azure Cosmos DB に対応付けられる、少数の操作をサポートしていました。

このライブラリの役割は、プロダクトチームが基盤の詳細を習得せずにデータを保存・取得できるシンプルな方法を提供することでした。Habitat は、データの種類、取得元や保存先、リクエストが許可されるかどうかなど、必要な処理を引き受けました。

プロダクトエンジニアは、スキーマ参照、ルーティング、認可、暗号化、シリアル化、リクエストシェーピング、接続プーリングを意識する必要がありません。データの取得元が Azure Cosmos DB、キャッシュ、その他のストレージのどれかを考える必要すらありませんでした。

図 02 · Habitat サービス

簡略化した Habitat のリクエストフロー

ストレージロジックを独立したサービスとして切り離すことで、デプロイ、可観測性、プラットフォーム強化を一元管理できるようにしました。

  • リクエスト
  • レスポンス

クライアント

OpenAI

Azure Cosmos DB

Habitat クライアント SDK
envoy
  • habitat-serviceプロセス 1
  • habitat-serviceプロセス 2
  • habitat-serviceプロセス 3
habitat-envoy
  • habitat-cosmos-db-us0
  • habitat-cosmos-db-us1
  • habitat-cosmos-db-eu0

この Python ライブラリはうまく機能し、セルフサービス型の Postgres や Azure Cosmos DB からの移行を中央で強く推進しなくても、OpenAI のプロダクトエンジニアに急速に普及しました。

プロダクト要件の進化に応じ、クライアント側キャッシュ、圧縮、暗号化などの機能をプロダクト開発者が共有ライブラリへ追加することも容易でした。

複数の複雑なプロダクトを支えるサービスの構築

2025 年半ばまでに、クライアント側実装としての Habitat は限界に達していました。Habitat 層が複雑化し、OpenAI のサービス数も増えたことで、後方互換性を保ったプロトコル変更は実行困難になっていました。

あるとき、最も重要なデータセットを地域分散された複数の Azure Cosmos DB アカウントへ移行し、単一リージョン障害の影響範囲を縮小しようとしました。この変更には、機能フラグで無効にした追加のルーティングロジックをクライアントへ導入し、全クライアントへの展開を確認してからフラグを有効にする必要がありました。

数十のサービスにまたがるデプロイを調整し、各チームと協力して展開するのに数日かかりました。有効化の前に、シャーディングロジックが正しいことを確認するため、シャドーイングも導入したいと考えました。その展開にもさらに数日かかりました。誤りに気づいてバグを修正する場合はどうでしょうか。さらに数日です。ようやくフラグを有効にできる段階になったところで、あるチームが無関係な理由からサービスを以前のバグのあるクライアントへロールバックし、懸命に回避しようとしていた障害が発生しました。

クライアントライブラリの変更には数十のサービス間で複雑な調整が必要で、そのプロセスは次第に脆弱かつ非効率になり、運用障害も起こりやすくなりました。今後のデプロイでこうした運用上の波及を抑えるため、Habitat を独立したサービスにすることを決めました。

ストレージロジックを独立したサービスとして切り離すことで、デプロイ、可観測性、プラットフォーム強化を一元管理できるようにしました。分散した更新を管理する代わりに、改善を中央で実装し、OpenAI の全プロダクトへ直ちにメリットを提供できるようになりました。

サービスを一元化すれば、強力なデータセキュリティとプライバシーの基本機能を適用する単一の要所も得られます。Habitat サービスでは、アクセス制御ポリシーの適用、監査ログの記録、Azure Cosmos DB など基盤ストレージリソースへのアクセス制限を一元的に実施できます。Habitat は、ユーザーデータを保護し、外部、内部、エージェントによる不正アクセスを防ぐうえで重要な役割を果たします。

Python サービスの大規模展開

サービスが必要なのは分かっていましたが、サービス化による Python 固有のオーバーヘッドがあっても、まだ Python から移行したくはありませんでした。高スループットのサービスに Python を使うと、ローカルでライブラリを実行する場合に比べ、ネットワーク遅延が増え、CPU とメモリのスケーリングコストも大幅に膨らみました。さらに、規模が 100 倍になれば Python の非効率性は許容できず、いずれ書き直すことになるのはほぼ確実だと認識していました。

しかし、これは戦略的に引き受ける技術的負債だと捉えました。当時の最優先目標はコストやリソースの最適化ではなく、プロダクト開発者の障壁を取り除き、プラットフォームを安定させることでした。短期的には Python サービスの性能上の妥協を受け入れることで、より差し迫った課題を優先し、コア API を確立して、堅牢なインフラを構築できました。

また、自社のコーディングモデルが急速に進歩すれば、将来の技術的な移行経路が簡単になるという計算のもとで賭けに出ました。Python から完全に移行する必要が生じる頃には、Codex と GPT によって移行を実現できると見込んだのです。その賭けは最終的に正しかったと証明されました。

Habitat を Python サービスとして運用することは性能面では最適でないものの、必要な選択でした。Python なら迅速に進められますが、だからといって警戒を解き、明らかに遅いレイテンシーを容認できるわけではありません。平均的なユーザーリクエストから数百回のデータベース呼び出しが発生する場合、ユーザーが体感するのは最も遅い呼び出しです。この規模で Python サービスを運用する最大の課題は、こうしたテールレイテンシーの管理だと分かりました。

asyncio の遅延追跡

asyncio を使うと Python で I/O バウンドなワークロードを並行実行できますが、Python の GIL を回避して CPU 並列性を得ることはできません。Habitat は I/O 負荷の高いリクエストプロキシに加え、ルーティング、圧縮、暗号化、チェックサム計算、下流のヘルスチェック、リクエストのシャドーイングやヘッジングなど、CPU 負荷の高い処理やバックグラウンドタスクも数多く担います。

サービス内に CPU 負荷の高いワークロードやバックグラウンドタスクが多数あるため、asyncio のスケジューリング遅延がリクエストのテールレイテンシーの大半を占めることも珍しくありません。最初のサービス公開に向けてチューニングする前、p99 以上のレイテンシーを示すリクエストのトレースを見ると、下流ストレージはすぐ応答しているのに、レスポンスを解析するコルーチンが再スケジュールされるまでリクエストが頻繁に停止していました。

図 03 · asyncio の遅延追跡

並行処理と CPU 並列処理の違い

Python の asyncio ではリクエストを並行処理できますが、CPU スレッドで同時に実行されるリクエストは一つだけです。CPU 処理が多い場合、これはリクエストのレイテンシーに大きく影響します。

CPU によるリクエスト/レスポンス処理Python のネットワーク読み書きCosmos 待機

CPU 処理量:低

短い Python 処理で I/O 待機が重複

CPU 処理量:高

長い Python 処理により、準備済みレスポンスが待機

0.0 / 40 例示単位

OpenAI の Python サービスでは、メモリ、CPU、ネットワーク、ディスク使用量に関する標準的な使用率と飽和度の指標に加え、asyncio ループとその負荷も監視し、それに応じて調整することが極めて重要です。

バックグラウンドタスクを定期的にスケジュールし、予定実行時刻と実際の実行時刻との差を記録することで、イベントループのスケジューリング遅延をリアルタイムで実測できます。使用率が高く、負荷の大きいタスクが多い状況では、プロセス当たりの同時リクエスト数がさほど多くなくても、数百ミリ秒、極端な場合は数秒に及ぶ大きなスケジューリングの揺らぎが発生します。

そのため、各プロセスが同時に処理するリクエストを少数に抑え、代わりに Python ワーカープロセスを大幅に増やしています。

機能フラグ設定に起因するテールレイテンシーの削減

最初のサービス公開時、稼働中のサービスを CPU プロファイリングした結果、asyncio の大きな遅延と、それに伴うテールレイテンシーの原因の一つが判明しました。Statsig(機能フラグを管理し、A/B テストなどにも使えるツール)経由で取得する機能フラグ設定を定期的に JSON 解析していたのです。

Statsig はデフォルトで、ジッターなしで毎分更新設定をポーリングするよう構成され、その設定には全サービスの本番環境向けルールがすべて含まれていました。さらに別の設計判断により、CPU 使用率を高めてレイテンシーを下げるため、ポッド当たり最大 8 個の Python プロセスを実行していました。この組み合わせにより、各ポッドでは毎分どこかの時点で全ワーカーが処理中のリクエストを止め、CPU サイクルを巨大な設定ファイルの解析に費やしていました。

CPU プロファイリングで根本原因を特定した後の修正は単純でした。対象を絞った小さな設定を配布し、更新間隔を延ばし、このようなバックグラウンドタスクにジッターを追加しました。

負荷分散と接続プールの管理

asyncio の遅延を低く保つには、サーバープロセス間でリクエストを適切に負荷分散することも重要です。接続プーリングも、調整しなければこれに逆行する場合があります。

クライアント側で接続をプールすると、多数のリクエストを並行実行する一つのクライアントプロセスが少数のサーバー接続しか確立せず、結果として全負荷を少数のプロセスだけへ送ることがあります。負荷分散方法を調整する前は、サービスの使用率に大きなばらつきがあり、一部のテール側プロセスが平均の 5~10 倍の同時リクエストを処理していました。

サービスの一部を過負荷にしていたクライアントを停止した後も、急増したトラフィックが収まってから長時間、一部のプロセスで性能低下が続いた偶発的なインシデントから、この問題を発見しました。実際、それらのプロセスでは劣化が暴走し、再起動するまで受信リクエストが増え続けていました。一度ポッドが過負荷になると、何らかの挙動によって、そのポッドへさらにトラフィックが固定されていました。これは、以前の仕事を通じて一部のチームメンバーが熟知していた種類の障害、すなわち準安定障害(新しいウィンドウで開く)でした。

接続プールが原因だと疑い、接続を再利用できる最長期間に上限を設けて検証しました。実際に劣化が抑えられ、調査の方向が正しいと確認できました。さらに調査したところ、Python の aiohttp TCPConnector はデフォルトで LIFO 方式により接続を再利用し、直近に返却された接続を次のリクエストに選ぶことが分かりました。通常、これは妥当なデフォルトです。最近使った接続を再利用すれば、トラフィックの急増に対応するため追加した接続をアイドルタイムアウトさせ、余分な接続の維持コストを削減できます。しかし、このケースでは準安定障害を引き起こしました。リクエストのバースト時には、過負荷で低速になったサーバーへのリクエストほど、接続がプールへ戻るのが遅くなります。そのため後続リクエストで選ばれる頻度が上がり、すでに処理が逼迫したポッドへトラフィックが徐々に集中しました。接続プールを修正して FIFO 方式で再利用するようにしたことで、このフィードバックループが断たれ、定常状態におけるリクエスト数のばらつきも減少しました。

図 04A · クライアント側接続プーリング

新しい処理を低速プロセスへ戻す LIFO

リクエストのバースト後、低速なサーバーの接続は最後にプールへ返却されます。LIFO では、同じ低速なサーバーに処理がさらに集中します。

最初のバーストが A、B、低速なプロセス C に到達します。

図 04B · クライアント側接続プーリング

接続再利用のフィードバックループを断つ FIFO

FIFO ではバースト後もアクティブな接続が多く残りますが、全サーバーへ公平に負荷を分散できます。

最初のバーストが A、B、低速なプロセス C に到達します。

現在は主に Istio と Envoy を利用し、OpenAI のインフラ全体で接続プーリングと、サーバー負荷をより適切に考慮した分散戦略を実現することで、この問題自体を回避しています。

下流リソースの過負荷防止

asyncio の遅延を抑えるために調整し、多数の Python プロセスを動かすことには副作用もあります。膨大な接続が一斉に押し寄せる「サンダリングハード」により、下流の依存先を簡単に圧倒してしまいます。

通常の毎日のデプロイでも、低速に進むよう調整しなければ、接続の入れ替わりによって大きな CPU 処理負荷が生じる可能性があります。接続リークによって NAT ゲートウェイが飽和し、ネットワーク全体が停止する場合もあります。これらは他のサービスでも珍しくない問題ですが、プロセス数が一桁多いことで発生し始めるしきい値が大幅に下がります。純粋なスループットだけを基に、定常状態でクライアントが処理を想定していないネットワーク関連リソースまで飽和することがよくあります。

接続の集約を最大化するためにも Envoy を利用しています。Envoy で Python の HTTP/1 接続を HTTP/2 へアップグレードして多重化を活用し、その接続をプールして接続時間を延長しています。また Envoy により、個々の独立した Python プロセスでは効果が低くなるレート制限やサーキットブレーカーを、一元的に実装できます。

図 05 · 接続の集約

同じリクエストを、より少ない接続で処理

接続プーリングと HTTP/2 の接続多重化により、下流への接続負荷を軽減できます。

リクエストレスポンスアイドル状態のキープアライブ

Habitat が機能を絞る理由

Python をここまでスケールできた理由の一つは、Habitat の API を制限し、リクエストコストを予測可能にしたことです。クライアントが巨大なテーブルスキャンや多数のテーブル間結合を招く任意の SQL クエリを組み立てられるようにせず、Habitat はシンプルな NoSQL API を提供します。強力な API を備えないことは、Habitat の設計で明示的に選んだトレードオフです。

シンプルで予測可能、かつ処理量が一定のリクエストに最適化することを目指しています。経験上、このようなシステムは格段にスケールしやすく、誤った実装や利用も起こりにくくなります。予測不能なファンアウトを伴うリクエストは、運用上危険です。分離や負荷分散を複雑にし、サービスとクライアントの双方にとってスケールしにくい急激なレイテンシー悪化を招きます。

Habitat と Azure Cosmos DB に移行する前、OpenAI のオンラインデータの大半は Postgres に保存されていました。当時は、クエリとスキーマの変更をすべて確認し、適切に動作してインデックス付きデータを参照することを確かめてから本番環境へリリースできました。チームとプロダクトの成長に伴い、この運用はすぐに限界を迎えました。高頻度の実行経路に追加された一つの高コストなクエリがデータベースを停止させ、障害の原因になることも頻発しました。

問題はコストの不均衡です。実行が難しく高コストな SQL クエリでも、記述自体は安く簡単にできます。Habitat ではこれを避け、高コストなクエリがクライアント側ですぐ分かるようにしています。Habitat を過負荷にし得る無制限のクエリはありません。複雑な結合やグラフ探索ではプロダクトチームにも難しい処理の一部を担ってもらうことで、全体としてより効率的な設計を促しています。

Habitat は、TAO(新しいウィンドウで開く) に着想を得た、クライアント定義のオブジェクト型とエッジ型を中心とする NoSQL API を提供します。クライアントはオブジェクトとエッジ、および相互の関係を事前定義しますが、各型の内容は定義しません。その関係はグラフに似ていますが、Habitat 自体は、特定オブジェクトの直接エッジを照会する以外の一般的なグラフ探索クエリをサポートしていません。

各オブジェクトと対応するエッジがストレージ層の同じパーティションに配置されるようグラフを分割していますが、オブジェクトと、そのエッジが指すリモートオブジェクトをデータベース層で同じ場所に配置するための特別な対応はしていません。その結果、このモデルは水平スケーリングに向けて容易に分割できます。一方、オブジェクト間の一回の移動でも、異なるリージョンにある別々の Azure Cosmos DB アカウントからの取得が必要になり得るため、グラフ探索は非効率です。

より複雑なクエリを必要とするクライアント向けには、Rockset 経由で利用できる Habitat のオフラインセカンダリビューも提供しています。変更データキャプチャ(CDC)を使い、オンラインストレージの変更を分離された Rockset インスタンスへほぼリアルタイムでストリーミングしています。各クライアントチームは、複雑なクエリの要件に合わせて自チームの Rockset インスタンスをスケールする責任を負います。

Rockset のプロビジョニングはクライアントの手間を増やしますが、現時点では適切なトレードオフだと考えています。シンプルなクエリをデフォルトにしつつ、複雑なクエリが必要な場合の回避手段も提供できるからです。この設計により、オンラインストレージを読み取り負荷の高い分析・検索ワークロードから分離しています。

Python から Rust への移行

Python 版の書き直しを 1 年延期したことで、急成長期には、より緊急で影響の大きい課題に集中できました。プラットフォームが成熟し、成長が加速し続けるなか、OpenAI でコア数が 2 番目に多いサービス(Envoy の規模では 4 番目)となったため、ついに Python から移行する時期が来ました。ピーク時には、Python で毎秒 2,000 万件を超えるリクエストを処理できました。

2026 年第 2 四半期、わずか 2 人のエンジニアが Codex と GPT‑5.5 を活用し、サービス全体を Rust で書き直しました。この新しい Rust サービスは現在、本番リクエストの 95% を処理しています。今後数週間で Python を完全に廃止する予定です。データによると、Rust サービスは Python 版に比べて CPU 効率が 6 倍、メモリ効率が 15 倍で、平均レイテンシーとテールレイテンシーも大幅に低下しています。今後のブログ記事で、さらに多くの知見を共有する予定です。

データベース層 Azure Cosmos DB の最適化

Python、そして現在の Rust サービスは、Habitat の一側面にすぎません。10 億人を超える ChatGPT ユーザーに対応するため、オンラインストレージを急速にスケールした方法を解説する本シリーズの第 2 部では、ストレージ層と、Habitat が 500 PB を超えるデータと毎秒 7,000 万件を超えるリクエストを処理する仕組みを紹介します。

フロンティア規模の OLTP システムに携わり、この種のエンジニアリングに関心がある方は、チームの求人をご覧ください

著者

Jon Lee、Chaomin Yu、Ben Ries