OpenAI が 9 億人のユーザー向けに低遅延音声 AI をどのように提供しているか(17 分読み)
OpenAI は、9 億人のユーザー規模に対応する低遅延音声 AI サービスを実現するために、独自のインフラと高度な最適化技術を開発・導入している。
キーポイント
大規模ユーザー対応の独自インフラ
OpenAI は 9 億人という膨大なユーザー数に対して低遅延を維持するため、既存のクラウド依存から脱却し、独自のインフラストラクチャを構築している。
音声 AI の最適化技術
リアルタイム性を確保するために、推論パイプライン全体の最適化やモデル圧縮など、高度な技術的工夫が施されている。
スケーラビリティとコスト効率の両立
ユーザー数が増加しても遅延が発生しないよう、システムのスケーラビリティを確保しつつ、運用コストも最適化している。
影響分析・編集コメントを表示
影響分析
このニュースは、音声 AI が単なる実験段階から、実社会で数億人規模に同時に利用される製品へと成熟したことを示す重要な転換点です。OpenAI が独自インフラを構築して遅延問題を解決したことは、他社も同様のスケールを目指す際の技術的ロードマップとして大きな影響を与えます。
編集コメント
9 億人という規模での低遅延維持は、音声 AI の実用化における最大の課題の一つを克服した画期的な事例です。独自インフラへの投資が、大規模サービス品質の根幹となっている点が注目されます。
Matic は、あなたの家を目にするように見て、あなたが望む通りに掃除ができる、世界初の視覚知能型ロボット掃除機です。Matic の主要機能:
- カメラのみで動作し、障害物を巧みに回避して移動します
- 床の種類を認識し、吸引と拭き取りを自動切り替えします
- 大きな車輪と高さを調整可能な清掃ヘッドが、厚手のラグも対応します
- 会話時の音量より静かな、55 デシベルの低騒音設計です
- ペットの毛を詰まらせたり絡めたりすることなく処理できます
- 1 つのバッグで乾いたゴミと湿ったゴミの両方を収集—オムツや塩、汚れた水はゲル化され、抗菌パウダーがカビを防ぎます
- バッグには毎回新しい HEPA フィルター(High Efficiency Particulate Air filter)が搭載されており、空気をより清潔に保ちます。洗浄や交換の必要はありません。
180 日間の返金保証付きで、Matic とともに自律型掃除体験を味わってください。
OpenAI は週に 9 億人のユーザーに対して音声 AI を提供しており、そのために WebRTC(Web Real-Time Communication)を利用しています。なぜなら、代替手段を選べばインターネットがライブオーディオを扱う方法をゼロから再構築する必要が生じるからです。
ただし、WebRTC は安定した IP アドレスとポートを持つサーバー向けに設計されており、Kubernetes はそれらのアドレスを一時的なものとみなします。この規模における従来の解決策は SFU(Selective Forwarding Unit)ですが、これはグループビデオ通話のような多者間ワークロードには適しています。一方、OpenAI のトラフィックの大半は、1 人のユーザーが 1 つのモデルと対話するという形態です。
これに対処するため、彼らのアーキテクチャはスタックを 2 つの部分に分割しています:
- ステートレスなリレーは、地理的エッジにおいてプロトコル認識型のパケットルーティングを処理します。
- ステートフルな送受信機は、すべての重い WebRTC の状態を管理します。
これらをつなぐ秘訣は、ICE ufrag(ICE 接続確立時にプロトコルがすでに交換するフィールド)を、リレーが新しいセッションの最初のパケットから読み取れるルーティングキーとして使用することです。Global Relay からユーザー空間の Go 実装、Redis キャッシュ、そして慎重なソケットレベルの最適化に至るまで、すべてがこの核となるアイデアの上に構築されています。
この記事では、OpenAI のエンジニアリングチームが直面した課題とともに、その全体像を詳細に解説します。
*免責事項:本投稿は Open AI エンジニアリングチームから公開された詳細に基づいています。不正確な点にご注意の場合はコメントをお願いします。
Voice AI は、会話のように感じられるか、それともトランシーバー(無線機)のように感じるかの違いです。その境界線はミリ秒単位で測られます。
ネットワークがユーザーの発言を聞き取り、応答する間に一時停止すると、その錯覚は崩れます。間延びした沈黙は awkward になり、割り込みは切り捨てられ、ユーザーは AI の話の途中でも強制的に遮らざるを得なくなります。これもまた失礼な行為です。つまり、会話が会話の速度で進む場合のみ、Voice AI は自然に感じられるのです。
その背後にあるより厳しい制約は、連続ストリームの性質です。音声はユーザーが話し終わった後の単一のアップロードとしてではなく、モデルに一定の流れとして届く必要があります。このストリームこそが、ユーザーがまだ話している最中にモデルが文字起こしを開始し、推論を行い、ツールを呼び出すことを可能にします。これが崩れると、体験はプッシュ・トゥ・トーク(押し話)に後退してしまいます。
OpenAI にとって、これらの制約は以下の 3 つの具体的な要件へと翻訳されます:
- システムは、ユーザーがどこにいようと、週次アクティブユーザー数 9 億人に到達できなければなりません。
- コネクション設定は、セッション開始と同時にユーザーが話し始められるほど迅速に完了する必要があります。
- 音声の往復時間(RTT)は低く安定した状態を維持し、ターンテイク(話者交代)が鮮明に感じられるようにする必要があります。
WebRTC は、この種の作業のために業界が構築したプロトコルです。これは、ファイアウォールを越えて 2 つのエンドポイントが互いに到達する方法を見つける ICE、チャネルの暗号化を行う DTLS、音声パケット用の SRTP、品質フィードバック用の RTCP など、より小さなプロトコルの集合体(バンドル)です。WebRTC の元々のアーキテクトの一人である Justin Uberti と、OpenAI が構築する基盤となる Pion ライブラリを維持している Sean DuBois は、現在ともに OpenAI で働いています。このようなプロトコルレベルの深さは、彼らが実装したアーキテクチャに現れています。
OpenAI の WebRTC インフラストラクチャの最初のバージョンは、Pion を基盤とした単一の Go サービスでした。この 1 つの場所で両方の役割を処理していました:
- シグナリング側では、サービスが SDP(セッションを記述するためにクライアントとサーバーが使用するフォーマット)の交渉を行い、コーデックを選択し、ICE 認証情報を生成してセッションを設定しました。
- メディア側では、サービスの WebRTC 接続をクライアントから終了し、推論、文字起こし、音声生成、ツール使用、オーケストレーションを実行するバックエンドサービスへのアップストリーム接続を維持しました。
この統合されたサービスは現在も ChatGPT の音声機能や Realtime API の WebRTC エンドポイント、およびいくつかの研究プロジェクトを支えており、その役割を十分に果たしてきました。OpenAI が直面した課題は、現代のクラウドインフラの多くを実行しているコンテナオーケストレーションシステムである Kubernetes 上でこれをどのように展開するかという点でした。
Kubernetes は計算リソースが安価で移動可能であると仮定しています。ポッド(Pod)は起動し、利用可能な容量がある場所にスケジューリングされ、しばらく実行された後、再スケジューリングまたは置き換えられます。一方、標準的な WebRTC の展開パターンはその逆を前提としています。この不一致は 2 つの具体的な場所で顕著に現れます。
1 つ目はポート枯渇の問題です。
WebRTC をデプロイする従来の方法は、セッションごとに UDP ポート 1 つを使用します。OpenAI のスケールでは、これはサービスあたり数万の公開 UDP ポートを意味します。クラウドロードバランサは少数のよく知られたポート向けに設計されているため、追加される各範囲がロードバランサの設定、ヘルスチェック、ファイアウォールポリシー、およびロールアウトの安全性において運用上の複雑さを増大させます。露出する表面領域もセキュリティ監査を困難にします。Kubernetes の自動スケールは、大規模で安定したポート範囲を予約するという要件と競合し、弾力性を脆弱なものにしてしまいます。
2 つ目はステートスティッキネス(状態の固定性)です。
サーバーごとに UDP ポート 1 つを実行し、その背後でセッションをデマルチプレックスすることでポートの問題は解決します。しかし、ICE や DTLS はステートフルなプロトコルです。セッションを開始したプロセスは、接続チェックの有効化、DTLS ハンドシェイクの完了、SRTP の復号化、および ICE リスタートのような後のセッション変更の処理のために、パケットを継続して受信し続ける必要があります。既存セッションのパケットが異なるプロセスに届いた場合、セットアップが失敗するか、メディアが切断されます。
両方の圧力は同じ答えを示しています。デプロイアーキテクチャは変更されなければなりませんが、クライアントエクスペリエンスは同一のまま維持されるべきです。
OpenAI が実装したアーキテクチャでは、パケットルーティングとプロトコル終端を分離しました。
ステートレスなリレーが前面に位置し、インターネットに対して小さな公開領域のみを提供します。一方、ステートフルなトランスシーバはその背後にあり、すべての重い WebRTC の状態を管理します。シグナリングは依然としてトランスシーバへ直接送信されます。メディアはまずリレーを経由して入力されます。
リレーの範囲は意図的に狭く設定されています。各パケットから宛先を選択するのに十分な部分を読み取り、残りは暗号化されたペイロードとして転送します。オーディオは通過中も暗号化されたまま保たれ、ICE 状態機械はトランスシーバーに留まり、コーデックのネゴシエーションは別の場所で行われます。クライアントの視点から見ると、WebRTC セッションはあらゆる点で通常通り動作しています。
トランスシーバーが記憶すべき WebRTC の部分を担当します。ICE 接続チェック、DTLS ハンドシェイク、SRTP 暗号化キー、そしてセッションライフサイクルはすべてここに存在します。トランスシーバーはハンドシェイクを完了し、実際のメディアの暗号化または復号化を行うエンドポイントです。
以下の図をご覧ください:
チームが評価したが却下した明白な代替案が存在しました。
SFU(Selective Forwarding Unit)とは、大規模な WebRTC における標準的なメディアサーバーアーキテクチャです。これは各参加者ごとに 1 つの WebRTC 接続を終端し、ストリームをそれらの間で選択的に転送します。AI ももう一つの参加者として加わります。
この方式は、グループ通話、教室、共同会議など、本質的に多人数を対象とした製品ではよく機能します。しかし OpenAI のワークロードは異なります。ほとんどのセッションは 1:1 で、一人のユーザーが一つのモデルと対話する形です。そのようなトラフィックに対して SFU モデルを採用するとオーバーヘッドが生じ、バックエンドサービス自体が WebRTC ピアのように振る舞うことを強いることになります。一方、トランスシーバーモデルであれば、バックエンドは通常のサービスとして維持できます。
SFU 方式を示す以下の図をご覧ください:
TURN も検討されましたが却下されました。
TURN は NAT 迂回に使用される標準的なプロトコル終端リレーです。問題は、TURN の割り当てを行うとメディアが流れる前にセットアップの往復遅延が発生し、サーバー間でそれらを移行または回復させるのが困難だということです。レイテンシに敏感なワークロードでは、これらの追加の往復遅延が問題となります。
この分割方式は原則としてポートと状態の問題を解決します。残っている問題は、リレーが最初のパケットを正しくルーティングできるようにすることです。
新しいセッションにおける最初のパケットが最も困難なものです。
その後のパケットは容易です。なぜなら、リレーには「このソース IP とポートからのパケットはこのトランスシーバーへ送られる」というマッピングが存在するからです。最初のパケットこそがこのマッピングを作成するものであり、リレーはそのパケット自体から宛先を特定する必要があります。
以下の図をご覧ください:
2 つの単純な選択肢が考えられました。
- ホットパスでのデータベース参照はレイテンシを追加し、別のサービスの健全性に対する堅牢な依存関係を生み出します。
- ランダムなトランスシーバーへのルーティングと内部転送は機能しますが、ホップ数が倍増してしまいます。
OpenAI は3 つ目の選択肢を選びました。
その答えは、WebRTC がすでに交換しているフィールドの中にあります。すべての WebRTC セッションには ICE ユーザー名フラグメント(ufrag と呼ばれます)が含まれており、これはセッションセットアップ中に生成され、STUN バインディングリクエストでエコーされます。STUN バインディングリクエストは、ICE が2つのエンドポイントが実際に互いに到達可能であることを検証するために使用するパケットであり、通常、クライアントがメディアパス上で最初に送信するものです。
ポイントは、OpenAI がシグナリング時にサーバー側で ufrag を生成していることです。彼らはそこに何を望んでも埋め込めるので、ルーティングメタデータをそこにエンコードしています。リレーは最初の STUN バインディング要求から ufrag を読み取り、ルーティングヒントをデコードし、セッションを所有するトランスシーバにパケットを転送するために必要な分だけ解析します。最初のパケット以降のすべてのパケットは確立されたセッションマッピングを通じて流れ、ufrag 解析ステップを完全にスキップします。
接続確立シーケンスの詳細を示す以下の図をご覧ください:
フリートの各トランスシーバは、内部 IP とポートにバインドされた 1 つのオペレーティングシステムエンドポイントである共有 UDP ソケットでリスニングしています。そのトランスシーバのすべてのセッションは、その背後で多重化されます。
シグナリング中、トランスシーバは SDP アサーで共有リレー VIP と UDP ポートを返します。VIP は仮想 IP アドレスであり、これは整個リレーフリートの前面に位置するため、クライアントは 203.0.113.10:3478 のように安定した単一の宛先を認識しますが、実際にはそのアドレスの背後に多数のリレーインスタンスが存在します。クライアント側からはパケットを送信する場所が 1 つだけあり、セッションの存続期間中それは変わりません。
リレーの状態は意図的に極めて小さく保たれています。これは、送信元アドレスからトランスシーバ宛先へのインメモリマップと、監視用のカウンタ、セッションクリーンアップ用のタイマを保持するものです。リレーインスタンスが再起動してマッピング情報を失った場合、次の STUN パケットが ufrag からマッピングを再構築します。回復速度を向上させるため、Redis キャッシュにはルートが確立された後の送信元から宛先へのマッピング情報が格納されます。再起動したリレーは、この Redis から即座にマッピング情報を参照できます。
ここで示される原則は広く一般化可能です。ホットパス上でデータが必要な場合、プロトコルが既に交換している内容を確認してください。ペイロード内のフィールドを解析することは本質的に無料です。新しい照合を行うことは、レイテンシの増加、依存関係の追加、そして故障する可能性のある要素の増大を意味します。
公開 UDP サーフェスが少数の固定アドレスに縮小されたことで、同じリレーパターンがグローバルに展開可能になりました。
Global Relay は OpenAI が運用する地理的に分散したリレーイングレスポイントの集合体です。これらすべてが上記で説明した同一のパケット転送動作を実行しています。唯一変化するのは、地図上の配置場所だけです。
地理的な分散により、最初のクライアントから OpenAI へのホップ距離が短縮されます。ユーザーに近い地理的・ネットワークトポロジー上の位置にあるリレーを通じてネットワークに進入するパケットは、まず遠隔地を経由して到達しなければならないパケットと比較して、はるかに容易に処理されます。実質的な効果として、OpenAI のバックボーンにトラフィックが到達する前に、レイテンシの低減、タイミングの安定化、および損失プロファイルの改善がもたらされます。
OpenAI は、シグナリング側において地理的および近接性のステアリングに Cloudflare を使用しています。セッションを設定する初期の HTTP または WebSocket リクエストは、近くのトランスシーバクラスターへルーティングされます。その後、リクエストコンテキストに基づいて、SDP アサーでクライアントに広告されるグローバルリレーのイングレスポイントが決定されます。ufrag には、メディアを適切なクラスターへルーティングし、かつそのクラスターのリレーから適切なトランスシーバへルーティングするために十分な情報が含まれています。
その結果、シグナリング経路とメディア経路の両方が、ユーザーに近い地点で OpenAI ネットワークに進入しますが、セッション自体はその全ライフタイムを通じて特定の 1 つのトランスシーバにアンカーされたままとなります。セットアップの往復時間と最初の ICE コネクティビティチェックが短縮されるため、ユーザーが発話を開始するまでの待ち時間が直接的に削減されます。
リレーは、ユーザースペースで実行されている Go サービスです。つまり、通常の UDP ソケットから読み取る通常のプロセスのことです。
Linux カーネルはネットワークインターフェースから UDP パケットを受け取り、リレーの IP とポートにバインドされたソケットへ配信します。その後、Go プロセスがそのソケットから読み込み、少量のフロー状態を更新し、各パケットを適切なトランスシーバへ転送します。
OpenAI はカーネルバイパスフレームワーク(ユーザースペースプロセスがネットワークカードのキューに直接ポーリングすることを可能にするもの)を検討しましたが、採用は見送りしました。バイパスは運用上の複雑さを増大させる代わりにパケットスループットを向上させます。チームの負荷量は、慎重に実装された Go 実装で処理可能な範囲内に収まっていました。
パフォーマンス負荷の大部分を担う実装上の選択肢は3つあります。
- SO_REUSEPORT は、同じマシン上の複数のワーカーが同一の UDP ポートをバインドできるようにする Linux ソケットオプションです。カーネルはこのオプションにより、着信パケットをそれらのワーカー間で分散処理するため、単一の読み込みループによるボトルネックが解消されます。
- runtime.LockOSThread は、各 UDP 読み取り用ゴルーチン(Go 言語における軽量スレッド)を特定の OS スレッドに固定します。SO_REUSEPORT と組み合わせることで、同一フローからのパケットが同じ CPU コア上に留まる傾向があり、キャッシュの局所性が向上し、コンテキストスイッチの回数が削減されます。
- パケット解析時に事前割り当て済みバッファを使用し、コピーを最小限に抑えることで、割り当てオーバーヘッドを低く保ち、Go のガベージコレクタへの負荷をかけないようにしています。
要点は、通常の最適化手法で十分だったということです。このリレーは、比較的小さなリソースフットプリントで OpenAI のグローバルなリアルタイムメディアトラフィックを処理しています。
あらゆるアーキテクチャにはトレードオフが伴うものであり、この設計にも理解しておくべきいくつかのトレードオフが存在します。
- この設計全体は、1 対 1 のセッションを中心に構築されています。もし OpenAI が今後、複数参加機能(グループ通話、単一の AI セッション内での複数の参加者、通話中の人間へのハンドオフ)を追加したい場合、このアーキテクチャの大部分を再構築する必要が生じるでしょう。トランシーバモデルと SFU をスキップする選択は、ほとんどのセッションが正確に 2 つのエンドポイントしか持たないという前提に基づいています。
- OpenAI はまた、カスタムインフラストラクチャの負担も引き受けました。標準的な SFU(Selective Forwarding Unit: 選択転送ユニット)にはドキュメント、コミュニティ、そして実戦で検証されたパターンが付属しています。一方、リレー、トランシーバ、およびそれらの間の調整はすべて内部コードです。このスタックに取り組むすべてのエンジニアは、内側から外側までこれを習得する必要があります。
- 「ステートレス」なリレーは、実際には精神的にのみステートレスであることがわかりました。これはメモリー内のフローテーブルを保持し、再起動時にそのテーブルを回復するために Redis キャッシュを使用します。このアーキテクチャが機能するのは、プロトコルが ufrag からテーブルを再構築できるからですが、ソフトな状態(soft state)も依然として状態です。
- 最後に、ufrag のトリックは、シグナリングの両端を制御することに依存しています。OpenAI はサーバー側の ufrag を生成するため、自由にルーティングメタデータを埋め込むことができます。市販のシグナリングスタックを使用するチームにとっては、この技術を直接適応させることが難しい場合があるでしょう。
- OpenAI が音声 AI のために構築したアーキテクチャは、特定の圧力に対する慎重な対応です。WebRTC は安定したサーバー向けに設計されましたが、現代のクラウドインフラストラクチャはその逆の前提に基づいて動作しています。OpenAI のチームには、WebRTC セッションをそもそも 1 つのプロセス内で実行する必要があるかどうかを判断するためのプロトコルの深さがありました。
その答えは、作業を2つの部分に分割するものです。ステートレスなリレーがユーザーの近くでパケットを転送します。一方、特定の場所に固定されたステートフルなトランスシーバーが、ICE、DTLS、SRTP、およびセッションライフサイクルを管理します。この2つの部分は、WebRTC のハンドシェイクに既に含まれている情報を通じて通信し、ルーティング判断をパケットパス自体上に維持します。
実装の選択は意図的にシンプルに保たれました。ユーザー空間でのGo言語、SO_REUSEPORT、スレッドピンニング、そして慎重なメモリ管理が、カーネルバイパスが解決するべき役割を果たしました。その結果、比較的小さなリレーの足跡で、週次9億人のユーザーを処理できる体制が整っています。
参考文献:**
- How OpenAI delivers low-latency voice AI at scale
原文を表示
Matic is the first visually intelligent robot vacuum that sees your home like you do, so it can clean how you want it to.**Matic’s hero features:
- Runs entirely on cameras to deftly navigate obstacles
- Recognizes floor types to auto-switch between vacuuming and mopping
- Big wheels and a height-adjustable cleaning head handle thick rugs
- Quieter than conversations at 55 dB
- Handles pet hair without clogging or tangling
- A single bag collects dry and wet waste—diaper-salts gel dirty water, antimicrobial powder prevents mold
- A fresh HEPA filter in every bag for cleaner air, no washing or replacing
Experience autonomous cleaning with Matic with a 180-day money-back guarantee.
OpenAI runs voice AI for 900 million users a week, and they use WebRTC for it because the alternative would mean reinventing how the internet handles live audio.
The catch is that WebRTC was designed for servers with stable IPs and ports, and Kubernetes treats those addresses as disposable. The conventional answer at this scale is an SFU, which suits multiparty workloads like group video calls, but OpenAI’s traffic is overwhelmingly one user talking to one model.
To deal with this, their architecture splits the stack into two pieces:
- A stateless relay handles protocol-aware packet routing at the geographic edge.
- A stateful transceiver owns all the heavy WebRTC state.
The trick that ties them together is using the ICE ufrag, a field the protocol already exchanges during setup, as a routing key that the relay can read off the first packet of a new session. Everything else, from Global Relay to the userspace Go implementation to the Redis cache and the careful socket-level optimizations, builds on top of that core idea.
In this article, we will look at the entire journey in detail and challenges the OpenAI engineering team faced.
*Disclaimer: This post is based on publicly shared *details* from the Open AI Engineering Team. Please comment if you notice any inaccuracies.*
Voice AI either feels like a conversation or it feels like a walkie-talkie. The line between those experiences is measured in milliseconds.
When the network pauses between hearing a user and responding, the illusion breaks. Pauses turn awkward, interruptions get clipped, and users are compelled to cut off the AI mid-sentence, which is also kind of rude. In other words, voice AI only feels natural if the conversation moves at the speed of speech.
The harder constraint underneath is the continuous-stream property. Audio has to arrive at the model as a steady flow, rather than as a single upload after the user finishes talking. That stream is what lets the model start transcribing, reasoning, and calling tools while the user is still speaking. The experience collapses into push-to-talk once it breaks.
For OpenAI specifically, those constraints translate into three concrete requirements:
- The system has to reach 900 million weekly active users wherever they are.
- Connection setup has to be completed quickly enough that users can start speaking as soon as a session begins.
- Round-trip time for audio has to stay low and stable so turn-taking feels crisp.
WebRTC is the protocol the industry built for this kind of work. It is a bundle of smaller protocols (ICE for figuring out how two endpoints reach each other across firewalls, DTLS for encrypting the channel, SRTP for the audio packets, and RTCP for quality feedback). Justin Uberti, one of WebRTC’s original architects, and Sean DuBois, who maintains the Pion library OpenAI builds on, both work at OpenAI today. That kind of protocol depth shows up in the architecture they shipped.
The first version of OpenAI’s WebRTC infrastructure was a single Go service built on Pion. It handled both jobs in one place:
- On the signaling side, the service negotiated SDP (the format clients and servers use to describe a session), selected codecs, generated ICE credentials, and set up sessions.
- On the media side, the service terminated WebRTC connections from clients and maintained upstream connections to the backend services that run the AI models, including inference, transcription, speech generation, tool use, and orchestration.
That combined service still powers ChatGPT voice, the Realtime API’s WebRTC endpoint, and several research projects, and it has handled that work well. The question OpenAI ran into was how to deploy it on Kubernetes, the container orchestration system that runs most modern cloud infrastructure.
Kubernetes assumes compute is cheap and movable. Pods come up, get scheduled wherever capacity exists, run for a while, then get rescheduled or replaced. Standard WebRTC deployment patterns assume the opposite. That mismatch shows up in two specific places.
The first is port exhaustion.
The conventional way to deploy WebRTC uses one UDP port per session. At OpenAI’s scale, that means tens of thousands of public UDP ports per service. Cloud load balancers were built for a handful of well-known ports, so each additional range adds operational complexity for load balancer config, health checks, firewall policy, and rollout safety. The exposed surface area also makes security audits harder. Kubernetes autoscaling clashes with the requirement to reserve large and stable port ranges, which makes elasticity brittle.
The second is state stickiness.
Running one UDP port per server and demultiplexing sessions behind it solves the port problem. ICE and DTLS, however, are stateful protocols. The process that started a session has to keep receiving its packets to validate connectivity checks, complete the DTLS handshake, decrypt SRTP, and process later session changes like ICE restarts. If a packet for an existing session lands on a different process, setup fails, or media breaks.
Both pressures point to the same answer. The deployment architecture has to change while the client experience stays identical.
The architecture OpenAI shipped splits packet routing from protocol termination.
A stateless relay sits at the front, presenting a small public footprint to the internet. A stateful transceiver sits behind it, owning all the heavy WebRTC state. Signaling still goes directly to the transceiver. Media enters through the relay first.
The relay’s scope is deliberately narrow. It reads enough of each packet to choose a destination, then forwards the rest as an opaque payload. Audio stays encrypted on the way through, ICE state machines stay with the transceiver, and codec negotiation happens elsewhere. From a client’s perspective, the WebRTC session looks normal in every way.
The transceiver owns the parts of WebRTC that have to remember things. ICE connectivity checks, the DTLS handshake, SRTP encryption keys, and the session lifecycle all live there. The transceiver is the endpoint that completes the handshakes and encrypts or decrypts the actual media.
See the diagram below:
There was an obvious alternative that the team evaluated and chose against.
An SFU, or Selective Forwarding Unit, is the standard media server architecture for WebRTC at scale. It terminates one WebRTC connection per participant and selectively forwards streams between them. The AI joins as another participant.
This works well for inherently multiparty products like group calls, classrooms, and collaborative meetings. OpenAI’s workload looks different. Most sessions are 1:1, with one user talking to one model. For that kind of traffic, the SFU model adds overhead and forces backend services to behave like WebRTC peers themselves. The transceiver model lets the backend stay an ordinary service.
See the diagram below that shows the SFU approach:
TURN was also considered and set aside.
TURN is the standard protocol-terminating relay used for NAT traversal. The trouble is that TURN allocations add setup round-trips before media can flow, and migrating or recovering them across servers is hard. For a latency-sensitive workload, those extra round-trip matters.
The split solves the port and state problems in principle. The remaining problem is making the relay route the first packet correctly.
The first packet of any new session is the difficult one.
Subsequent packets are easy because the relay has a mapping that says that packets from this source IP and port go to this transceiver. The first packet is what creates that mapping, so the relay has to figure out where to send it from the packet itself.
See the diagram below:
Two naive options were present:
- A database lookup on the hot path adds latency and a hard dependency on another service staying healthy.
- Routing to a random transceiver and forwarding internally works, but doubles the hop count.
OpenAI chose a third option.
The answer lives inside a field that WebRTC already exchanges. Every WebRTC session carries an ICE username fragment, called the ufrag, which is produced during session setup and echoed in STUN binding requests. STUN binding requests are the packets ICE uses to verify that two endpoints can actually reach each other, and they are usually the first thing a client sends on the media path.
The trick is that OpenAI generates the server-side ufrag during signaling. They can put whatever they want in it, so they encode routing metadata into it. The relay parses just enough of the first STUN binding request to read the ufrag, decode the routing hint, and forward the packet to the transceiver that owns the session. Every packet after the first one flows through the established session mapping, which skips the ufrag parsing step entirely.
See the diagram below that shows the connection establishment sequence in detail:
Each transceiver in the fleet listens on a shared UDP socket, which is one operating system endpoint bound to an internal IP and port. All sessions for that transceiver multiplex behind it.
During signaling, the transceiver returns a shared relay VIP and UDP port in the SDP answer. A VIP is a virtual IP address that fronts the entire relay fleet, so the client sees one stable destination like 203.0.113.10:3478, even though many relay instances sit behind that address. From the client’s side, there is one place to send packets, and it stays the same for the life of the session.
The relay’s state is purposefully tiny. It holds an in-memory map of source address to transceiver destination, plus some counters for monitoring and timers for session cleanup. If a relay instance restarts and loses the mapping, the next STUN packet rebuilds it from the ufrag. To make recovery faster, a Redis cache holds the source-to-destination mapping once a route is established. A restarted relay can look up the mapping from Redis immediately.
The principle here generalizes well. When we need data on the hot path, look at what the protocol is already exchanging. A field on the payload is essentially free to parse. A new lookup costs latency, a dependency, and one more thing that can break.
Once the public UDP surface was reduced to a small fixed set of addresses, the same relay pattern became deployable globally.
Global Relay is OpenAI’s fleet of geographically distributed relay ingress points. All of them run the identical packet-forwarding behavior described above. The only thing that changes is where on the map they sit.
Geographic distribution shortens the first client-to-OpenAI hop. A packet entering the network at a relay close to the user, in both geography and network topology, has a much easier time than a packet that has to traverse the public internet to reach a distant region first. The practical effect is lower latency, more stable timing, and a cleaner loss profile before traffic reaches the OpenAI backbone.
OpenAI uses Cloudflare for geographic and proximity steering on the signaling side. The initial HTTP or WebSocket request that sets up a session is routed to a nearby transceiver cluster. The request context then determines which Global Relay ingress point gets advertised back to the client in the SDP answer. The ufrag carries enough information for Global Relay to route media to the right cluster, and for the cluster’s relay to route to the right transceiver.
The result is that both the signaling and the media paths enter the OpenAI network at points close to the user, while the session itself stays anchored to one specific transceiver for its full lifetime. The setup round-trip and the first ICE connectivity check both shorten, which directly reduces how long a user waits before they can start speaking.
The relay is a Go service running in userspace, which is to say a regular process that reads from a regular UDP socket.
The Linux kernel receives UDP packets from the network interface, delivers them to a socket bound to the relay’s IP and port, and the Go process reads from that socket, updates a small amount of flow state, and forwards each packet to the right transceiver.
OpenAI evaluated kernel-bypass frameworks (which let a userspace process poll the network card’s queues directly) and chose to stay away. Bypass raises packet throughput at the cost of operational complexity. The team’s workload fit inside what a careful Go implementation could handle.
Three implementation choices carry most of the performance load.
- SO_REUSEPORT is a Linux socket option that lets multiple workers on the same machine bind the same UDP port. The kernel then distributes incoming packets across those workers, which removes the bottleneck of a single read loop.
- runtime.LockOSThread pins each UDP-reading goroutine (a lightweight thread in Go) to a specific OS thread. Combined with SO_REUSEPORT, this tends to keep packets from the same flow on the same CPU core, which helps cache locality and reduces context switching.
- Pre-allocated buffers and minimal copying during packet parsing keep allocation overhead low and avoid putting pressure on Go’s garbage collector.
The takeaway is that ordinary optimizations were enough. The relay handles OpenAI’s global real-time media traffic on a relatively small footprint.
Every architecture comes with tradeoffs, and this one carries several worth understanding.
- The whole design is built around 1:1 sessions. If OpenAI ever wants to add multiparty features (group voice calls, multiple participants in a single AI session, human handoff during a call), large parts of this architecture would probably need rework. Both the transceiver model and the choice to skip SFU rely on the assumption that most sessions have exactly two endpoints.
- OpenAI also took on a custom infrastructure burden. A standard SFU comes with documentation, a community, and battle-tested patterns. The relay, the transceiver, and the coordination between them are all internal code. Every engineer who works on this stack has to learn it from the inside out.
- The “stateless” relay turns out to be stateless mostly in spirit. It holds an in-memory flow table and uses a Redis cache to recover that table across restarts. The architecture works because the protocol can rebuild the table from the ufrag, but the soft state is still a state.
- Lastly, the ufrag trick depends on controlling both ends of signaling. OpenAI generates the server-side ufrag, so they can embed routing metadata in it freely. A team that uses an off-the-shelf signaling stack might find this technique harder to adapt directly.
The architecture OpenAI built for voice AI is a careful response to a specific pressure. WebRTC was designed for stable servers. Modern cloud infrastructure runs on the opposite assumption. OpenAI’s team had the protocol depth to determine whether a WebRTC session needs to live in one process at all.
Their answer separates the work into two pieces. A stateless relay forwards packets near the user. A stateful transceiver, anchored in one place, owns ICE, DTLS, SRTP, and the session lifecycle. The two pieces communicate through information that’s already in the WebRTC handshake, which keeps the routing decision on the packet path itself.
The implementation choices stayed deliberately simple. Userspace Go, SO_REUSEPORT, thread pinning, and careful memory management did the work that kernel bypass solves. The result handles 900 million weekly users on a relatively small relay footprint.
References:**
- How OpenAI delivers low-latency voice AI at scale
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み