OpenAI がどう8億人のユーザをさばいてるか
そんなタイトルのビデオが出ていたので、内容をまとめてみました。
こちらが、オリジナルのブログでした。
基本構成と進化
OpenAIは現在、たった1つのPostgreSQLプライマリインスタンスと50のリードレプリカ(Read Replicas)だけで、8億人のユーザー基盤を運用しています。最初から水平スケーリングを行うデータベースを採用したわけではなく、初期はアプリケーションロジックの最適化、データベースパラメータの調整、垂直スケーリング(ハードウェアの増強)、リードレプリカの追加といったシンプルな構成からスタートしました。
直面した課題
規模が拡大するにつれ、以下のような課題が発生しました:
- キャッシュミスと高負荷: キャッシュミスが発生するとデータベースへの同期負荷が急増し、連鎖的な障害を引き起こすリスクがある
- 複雑な結合(Join)処理: 複数のテーブルをまたぐ高価な結合処理がCPUを飽和させ、タイムアウトを引き起こす
- 書き込み(Write)の非効率性: PostgreSQLのMVCC(多版型同時実行制御)の仕組み上、行を更新するたびに新しい行のコピーが作成されるため、書き込み増幅(Write Amplification)が発生します。また、不要になった行を整理する「Vacuum」プロセスが必要となり、これも読み取り負荷を増大させます
具体的な解決策と最適化手法
これらの課題に対処するため、OpenAIは以下の多角的なアプローチを採用しています。
-
シャーディング(Sharding)への移行
既存のPostgreSQLの負荷を減らすため、シャーディング可能なワークロードの一部を特定し、AzureのCosmos DB(ネイティブでシャーディング対応)へ移行しました。新規のワークロードについては、最初からシャーディングされた環境で動作するように設計されています。 -
プライマリデータベースの負荷軽減
- Lazy Writes(遅延書き込み): リアルタイム性が不要な処理は非同期のバッチ処理として書き込むことで、データベースへの即時負荷を減らしました
- 厳格なレート制限: 過剰な書き込みからデータベースを保護するためにレートリミットを適用しました
- クエリの最適化: 12個のテーブルを結合するような高負荷なクエリを廃止し、アプリケーション層で複数の単純なSelect文に分割して処理するように変更しました。これにより、リードレプリカやキャッシュを有効活用できるようになりました。また、ORM(Object-Relational Mapping)が生成する非効率なクエリ(N+1問題など)を監査し、書き換えを行いました
- 可用性の向上
- ホットスタンバイ(Hot Standby): プライマリがダウンした場合に備え、トラフィックを処理せず同期だけを行うホットスタンバイを用意し、即時のフェイルオーバー(切り替え)を可能にしています
- 部分的な可用性: プライマリがダウンしても、リードレプリカへの読み取りは継続させることで、完全な停止(Outage)を防いでいます
-
ワークロードの分離(Isolation)
特定のユースケースが他のリクエストに悪影響を与えないよう(Noisy Neighbor問題の回避)、ユースケースごとに使用するリードレプリカを専用に割り当てるルーティングを行っています。 -
コネクションプーリング(Connection Pooling)
PostgreSQLは新しい接続ごとに新しいプロセスを生成するため、接続コストが高いという特性があります。これを解決するため、PgBouncerというプロキシを導入し、データベースへの接続をプールして再利用することで、接続確立のレイテンシを50msから5ms程度まで短縮し、アクティブな接続数を抑制しています。 -
キャッシュ戦略(Cache Locking)
キャッシュミス発生時に、全てのリクエストが同時にデータベースへ殺到するのを防ぐため、「キャッシュロッキング(またはRequest Hedging)」を採用しています。これは、1つのリクエストだけがデータベースに行ってキャッシュを更新し、他のリクエストはその完了を待つという仕組みです。
将来のスケーリング戦略:カスケードレプリケーション
リードレプリカの数には限界があり、無限に追加することはできません。そこでOpenAIは現在、カスケードレプリケーション(Cascading Replication)をテストしています。これは、プライマリから直接すべてのレプリカにデータを送るのではなく、まず中間層のレプリカにデータを送り、そこからさらに複数の末端リードレプリカへ分岐させる手法です。これにより、単一プライマリの制限を超えて読み取り性能をスケールさせることが可能になります。
まとめ
8億人を捌くインフラは勉強になりますね。MySQL系ばかり使っているので、PostgreSQL系はあまりなじみがないのですが、高負荷時にやることは似てるなと思いながら見てました。1つのプライマリでやってるというのは怖いような恐いような・・・
