본문으로 건너뛰기

© 2026 Molayo

HN분석2026. 05. 07. 23:54

How OpenAI delivers low-latency voice AI at scale

요약

OpenAI는 대규모 사용자 기반에서 자연스럽고 지연 없는 음성 AI 상호작용을 제공하기 위해 WebRTC 스택을 재건축했습니다. 이 아키텍처의 핵심은 클라이언트 연결을 종료하고 미디어와 이벤트를 추론, 전사, 음성 생성 등의 내부 프로세스로 변환하는 'transceiver' 모델입니다. 이는 1:1 대화 시나리오에 최적화되어 있으며, WebRTC 표준을 기반으로 안정적인 저지연 오디오 스트리밍과 복잡한 AI 워크플로우를 통합합니다.

핵심 포인트

  • 대규모 음성 AI 상호작용에는 지연 시간(latency) 최소화와 일관된 대화 속도 유지가 필수적입니다.
  • OpenAI는 WebRTC의 표준 기능을 활용하여 글로벌 규모에서 안정적인 실시간 미디어 전송을 보장합니다.
  • 1:1 대화 시나리오에 맞춰, 클라이언트 연결을 종료하고 내부 AI 프로세스로 변환하는 'transceiver' 아키텍처를 채택했습니다.
  • WebRTC는 ICE, DTLS, SRTP 등 복잡한 표준 프로토콜 스택을 제공하여 개발자가 미디어 인프라 자체보다 AI 로직에 집중할 수 있게 합니다.

음성 AI 가 자연스럽고 느껴지려면 대화 속도가 말의 속도와 일치해야 합니다. 네트워크가 방해할 때 사람들은 즉시 어색한 침묵, 잘라진 중재, 또는 지연된 바리진 (barge-in) 을 듣습니다. 이는 ChatGPT 음성, Realtime API 로 개발하는 개발자, 상호작용 워크플로우에서 작업하는 에이전트, 사용자가 말하고 있는 동안 오디오를 처리해야 하는 모델 모두에게 중요합니다.

OpenAI 의 규모에서는 이것이 세 가지 구체적인 요구사항으로 이어집니다:

  • 9 억 명 이상의 주간 활성 사용자에 대한 글로벌 접근성
  • 세션이 시작되자마자 사용자가 즉시 말을 시작할 수 있도록 빠른 연결 설정
  • 저잡음과 안정적인 미디어 라운드트립 시간 (jitter 와 packet loss 를 낮게 유지), 턴테이크가 날카롭게 느껴지도록

OpenAI 에서 실시간 AI 상호작용을 담당하는 팀은 규모가 커지면서 충돌하기 시작한 세 가지 제약을 해결하기 위해 WebRTC 스택을 재건축했습니다: 한 세션당 하나의 포트를 사용하는 미디어 종말 처리는 OpenAI 인프라에 잘 맞지 않으며, 상태 기반 ICE (Interactive Connectivity Establishment) 와 DTLS (Datagram Transport Layer Security) 세션은 안정적인 소유가 필요하며, 글로벌 라우팅은 첫 홉의 지연 시간을 낮게 유지해야 합니다. 이 글에서는 클라이언트에서 표준 WebRTC 동작을 보존하면서 OpenAI 의 인프라 내부에서 패킷이 어떻게 라우팅되는지 변경하는 데 구축한 relay plus transceiver 아키텍처를 살펴보겠습니다.

WebRTC 는 브라우저, 모바일 앱, 서버 간에 저지연 오디오, 비디오, 데이터를 전송하기 위한 오픈 표준입니다. 보통 피어 투 피어 (peer-to-peer) 호출과 관련이 있지만, 클라이언트에서 서버로 실시간 시스템을 구축하는 실용적인 기반이기도 합니다. 이는 상호작용 미디어의 어려운 부분을 표준화하기 때문입니다: 연결 설정을 위한 ICE 와 NAT (Network Address Translation) 트래버스, 암호화된 전송을 위한 DTLS 와 SRTP (Secure Real-time Transport Protocol), 오디오 압축 및 해독을 위한 코덱 협상, 품질 제어를 위한 RTCP (Real-time Transport Control Protocol), 그리고 에코 제거와 jitter 버퍼링과 같은 클라이언트 측 기능입니다.

이 표준화는 AI 제품에 중요합니다. WebRTC 가 없다면 각 클라이언트는 NAT 를 통한 연결 설정, 미디어 암호화, 코덱 협상 (전송 및 해독을 위해 선택된 coder-decoders), 그리고 변화하는 네트워크 조건에 적응하기 위한 다른 답변이 필요합니다. WebRTC 는 이미 브라우저와 모바일 플랫폼에서 구현된 프로토콜 스택을 기반으로 구축할 수 있으며, 실시간 미디어를 모델과 연결하는 인프라에 대한 자신의 작업을 집중할 수 있습니다.

또한 우리는 웹RTC 생태계 자체를 기반으로 합니다: 성숙한 오픈소스 구현과 브라우저, 모바일 앱, 서버 간의 상호운용성을 유지하는 표준 작업. Justin Uberti (WebRTC 의 원래 아키텍트 중 한 명) 와 Sean DuBois (Pion 의 생성자 및 관리자) 의 기초 작업이 저 수준 트랜스포트, 암호화, 혼잡 제어 동작을 재발명하기보다 우리 팀이 검증된 미디어 인프라를 기반으로 구축할 수 있게 했습니다. Justin 과 Sean 이 둘 다 이제 OpenAI 에서 동료로 일하고 있어 WebRTC 와 실시간 AI 를 더 가깝게 가져오도록 어떻게 안내하는지 돕는 것은 운이 좋았습니다.

AI 에서는 오디오가 연속적인 스트림으로 도착하는 것이 가장 중요한 속성입니다. 말한 에이전트는 사용자가 아직 말하고 있는 동안 전사, 추론, 도구 호출, 또는 음성 생성을 시작할 수 있습니다. 이는 대화형 시스템과 푸시 투 톡 (push-to-talk) 과 같은 시스템의 차이점입니다.

WebRTC 를 선택한 후 다음 질문은 어디에서 종결할 것인가 (예: 에지에서 WebRTC 연결을 수용하고 소유) 및 이를 추론 백엔드와 어떻게 연결할 것인가였다. 종결 (termination) 이 중요한 이유는 실시간 세션 상태, 미디어 전송, 라우팅, 지연 시간, 그리고 실패 격리 처리 방식을 결정하기 때문이다.

SFU (selective forwarding unit) 는 각 참여자로부터 하나의 WebRTC 스트림을 수신하고 다른 참여자에게 선택적으로 스트림을 전달하는 미디어 서버이다. 이 모델에서 SFU 는 각 참여자에 대해 별도의 WebRTC 연결을 종료하며 AI 는 세션의 다른 참여자로 참가한다. 이는 그룹 통화, 강의실, 또는 협업 회의와 같이 본질적으로 다자간인 제품에 적합할 수 있다. 오디오 코덱, RTCP 메시지, 데이터 채널, 녹화, 그리고 스트림별 정책이 한 곳에 통합된다.

클라이언트에서 AI 로 가는 제품에서도 SFU 는 종종 기본 시작점으로 사용되며, 팀은 신호 처리, 미디어 라우팅, 녹화, 관찰 가능성 및 인간 교대 또는 추가 참여자 추가와 같은 미래 확장을 위해 하나의 검증된 시스템을 재사용할 수 있기 때문이다.

우리 작업 부하 (workload) 는 다르다. 대부분의 세션은 1:1 형태이며 — 한 사용자가 한 모델과 대화하거나, 한 애플리케이션이 실시간 에이전트와 대화하는 경우 — 모든 턴에서 지연 시간 민감도가 있다. 이 형태의 트래픽을 위해 우리는 transceiver 모델을 선택했다: WebRTC 에지 서비스는 클라이언트 연결을 종료한 후 미디어와 이벤트를 추론, 전사, 음성 생성, 도구 사용, 그리고 오케스트레이션에 더 간단한 내부 프로토콜로 변환한다.

이 설계에서 transceiver 는 ICE 연결성 확인, DTLS 핸드셰이크, SRTP 암호화 키, 세션 라이프사이클을 포함한 WebRTC 세션 상태를 소유하는 유일한 서비스이다. 여기서 "종결" 은 transceiver 가 그 핸드셰이크를 완료하고 미디어를 암호화하거나 복호화하는 엔드포인트라는 것을 의미한다. 해당 상태를 한 곳에 유지함으로써 세션 소유권을 추리하기 쉬워졌으며, 백엔드 서비스는 WebRTC 피어 자체로 행동하는 대신 일반 서비스처럼 확장할 수 있게 되었다.

transceiver 모델을 선택한 후 첫 구현은 Pion 을 기반으로 구축된 단일 Go 서비스였으며, 신호 처리와 미디어 종결을 모두 담당했다. 이는 ChatGPT 음성, Realtime API 의 WebRTC 엔드포인트, 그리고 여러 연구 프로젝트를 구동한다.

운영적으로 transceiver 서비스는 두 가지 작업을 수행한다:

  • 신호 처리: SDP 협상, 코덱 선택, ICE 인증서 및 세션 설정
  • 미디어: 다운스트림 WebRTC 연결을 종료하고 추론 및 오케스트레이션에 대한 백엔드 서비스에 상류 연결을 유지한다.

우리는 이 서비스가 우리 인프라의 나머지 부분과 같이 작동하기를 원했다: Kubernetes 에서 워크로드가 확장 및 축소될 수 있으며, 수요 변화에 따라 호스트를 이동할 수 있다. 그러나 일반적인 한 포트당 세션 WebRTC 모델은 그 환경에 잘 맞지 않으며, 이는 추가, 제거 또는 재스케줄링이 이루어질 때 노출하고 관리하기 어려운 대형 공개 UDP 포트 범위에 의존하기 때문이다.

첫 번째 문제는 한 포트당 세션 모델 자체였다. 고 컨커런시 (high concurrency) 에서 그것은 매우 큰 UDP 포트 범위를 노출하고 관리한다는 것을 의미한다.

  • 클라우드 로드 밸런서와 Kubernetes 서비스는 서비스당 수만 개의 공개 UDP 포트를 기반으로 설계되지 않았습니다. 각 추가 범위는 로드 밸런서 설정, 건강 체크, 방화벽 정책 및 배포 안전성에서 운영 복잡성을 증가시킵니다.
    3 - 대규모 UDP 포트 범위는 보안이 어렵습니다. 이는 외부로 접근 가능한 표면적을 확장하고 네트워크 정책을 감사하기 어렵게 만들기 때문입니다.
  • 또한 자동 스케일링에 적합하지 않습니다. Kubernetes 에서 포드는 끊임없이 추가, 제거 및 재스케줄링됩니다. 각 포드가 큰 안정적인 포트 범위를 예약하고 광고하도록 요구하면 그 탄력성이 취약해집니다.
    4
    이것이 많은 WebRTC 시스템이 서버당 하나의 UDP 포트로 이동하는 이유입니다. 해당 포트 뒤에 애플리케이션 레벨의 다중화 (demultiplexing) 가 있습니다.5

서버당 단일 포트 설계는 포트 수 문제를 해결하지만, 플레트 (fleet) 를 통해 각 세션을 소유권 보존이라는 두 번째 문제를 도입합니다.

ICE 와 DTLS 는 상태ful 프로토콜입니다. 세션을 생성한 프로세스는 연결성 확인을 검증하고, DTLS 핸드셰이크를 완료하며, SRTP 을 암호화 해제하고, ICE 재시작과 같은 후기 세션 변경을 처리하기 위해 해당 세션의 패킷을 계속 수신해야 합니다. 동일한 세션의 패킷이 다른 프로세스에 도착하면 설정이 실패하거나 미디어가 끊길 수 있습니다.

그것은 작은 고정 UDP 표면적을 공개 인터넷에 노출시키되, 여전히 해당 WebRTC 세션을 소유하는 트랜시비어 (transceiver) 에 모든 패킷을 라우팅하는 구체적인 목표를 제시했습니다.

여러 방법을 평가했습니다. TURN (NAT 를 돌아다니는 릴레이 사용), 엣지 릴레이에서 클라이언트 할당을 종료하고 대신 대역폭을 전달하는 방법 등을 포함했습니다.2

|
|
|
| | Unique IP:port per session (also known as native direct UDP) | Direct client-to-server media path No forwarding layer in the data path | Requires one public UDP port per session Large port ranges are difficult to expose and secure Poor fit for Kubernetes and cloud load balancers |
| | Unique IP:port per server | Much smaller public UDP footprint than per-session exposure One shared socket per server can demultiplex many sessions | Works cleanly on a single host, but not across a shared load-balanced fleet by itself Session demultiplexing on a single host only helps after a packet reaches that host; across a load-balanced fleet, the first packet can still land on the wrong instance, so you still need a deterministic way to steer each session to the process that owns it |
| | TURN relay (protocol-terminating) | Clients only need to reach the TURN relay address and port Can centralize policy at the edge | TURN allocations add setup round trips Moving or recovering allocations across TURN servers is still difficult |
| | Stateless forwarder + stateful terminator (OpenAI's relay + transceiver) | Small public UDP footprint Transceiver still owns the full WebRTC session | Adds one forwarding hop before media reaches the owning transceiver Requires custom coordination between relay and transceiver |

우리가 출시한 아키텍처는 패킷 라우팅과 프로토콜 종료를 분리합니다. 세션 설정은 여전히 트랜시비어 (transceiver) 에 도달하지만, 미디어는 먼저 릴레이를 통해 들어옵니다. 릴레이는 작은 공개 표면적을 가진 경량 UDP 전달 레이어이며, 트랜시비어는 그 뒤에 있는 상태ful WebRTC 엔드포인트입니다.

릴레이는 미디어를 복호화하거나, ICE 상태 머신을 실행하지 않으며, 코덱 협상에도 참여하지 않습니다. 릴레이는 목적지를 선택하기 위해 충분한 패킷 메타데이터를 읽은 후 해당 세션을 소유하는 트랜시버에 패킷을 전달합니다. 트랜시버는 여전히 정상적인 WebRTC 흐름을 보이며 모든 프로토콜 상태를 소유합니다. 클라이언트의 관점에서는 WebRTC 세션에 대한 어떤 변화도 없습니다.

첫 번째 패킷 라우팅은 이 설정의 핵심 단계입니다. 릴레이는 패킷 경로 자체에서 세션이 존재하기 전에 클라이언트로부터 첫 번째 패킷을 라우팅해야 하며, 외부 조회 서비스에 일시 정지하는 것이 아니라야 합니다.

모든 WebRTC 세션에는 프로토콜 네이티브 라우팅 훅이 이미 포함되어 있습니다: ICE 사용자명 프래그먼트, 또는 ufrag입니다. 이는 세션 설정 중에 교환되는 짧은 식별자로 STUN 연결성 체크에서 반사됩니다. 우리는 서버 측 ufrag 을 생성하여 릴레이가 목적지 클러스터와 소유 트랜시버를 추론하기에 충분한 라우팅 메타데이터만 포함되도록 합니다.

신호링 동안, 트랜시버는 세션 상태를 할당하고 SDP 답변에서 공유 릴레이 VIP 와 UDP 포트를 반환합니다. VIP 는 릴레이 플레트를 프론트하는 가상 IP 주소입니다; 포트와 함께하면 클라이언트는 여러 릴레이 인스턴스가 뒤쪽에 있더라도 단일 안정적인 목적지, 예를 들어 203.0.113.10:3478을 가집니다. 클라이언트의 첫 번째 미디어 경로 패킷은 일반적으로 STUN (Session Traversal Utilities for NAT) 바인딩 요청이며, ICE 는 이를 사용하여 광고된 주소에 도달할 수 있는지 확인합니다.

릴레이는 첫 번째 STUN 패킷의 최소한의 내용을 파싱하여 서버 ufrag 을 읽으러, 라우팅 힌트를 디코딩하고 해당 소유 트랜시버에 패킷을 전달합니다. 각 트랜시버는 공유 UDP 소켓을 경청하며, 이는 세션당 하나의 소켓이 아닌 내부 IP:포트에 바인드된 하나의 운영체제 엔드포인트를 의미합니다. 릴레이가 클라이언트의 원천 IP:포트에서 해당 트랜시버 목적지에 세션을 생성한 후, 이후 DTLS, RTP, RTCP 패킷은 ufrag 을 다시 디코딩하지 않고 세션 내에서 흐릅니다.

릴레이의 세션은 의도적으로 최소로 구성되며, 패킷 전달을 알리기 위한 인메모리 세션과 모니터링을 위한 필요한 카운터 및 세션 만료 및 정리용 타이머만 포함합니다. 이 설계 선택은 패킷 라우팅을 직접 패킷 경로에 유지합니다. 릴레이가 재시작하여 세션을 잃으면, 다음 STUN 패킷이 ufrag 라우팅 힌트에서 세션을 다시 구축합니다. 더 신뢰성을 높이기 위해, 루트는 설정된 후 <클라이언트 IP + 포트, 트랜시버 IP + 포트> 매핑을 저장하기 위해 Redis 캐시를 사용하여 다음 STUN 패킷 도착 전에 훨씬 일찍 복구할 수 있습니다.

우리가 공개 UDP 표면을 소수의 안정적인 주소와 포트로 줄였을 때, 전역적으로 동일한 릴레이 패턴을 배포할 수 있었습니다. 글로벌 릴레이는 지리적으로 분산된 릴레이 진입점의 플레트이며, 모두 동일한 패킷 전달 동작을 구현합니다.

광범위한 지리적 진입은 클라이언트에서 OpenAI 로의 첫 번째 홉을 단축시키며, 패킷이 사용자의 지리와 네트워크 토폴로지 근처에 있는 릴레이로 우리 네트워크에 진입할 수 있기 때문입니다. 실제로는 트래픽이 our backbone 에 도달하기 전에 더 낮은 지연 시간, 더 적은 자이팅, 그리고 더 적은 피할 수 없는 손실 버스트를 의미합니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 HN AI Posts의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
2

댓글

0