---
title: "음성 AI에 WebRTC 쓰지 말라는 꽤 빡센 반론"
published: 2026-05-07T17:11:59.000Z
canonical: https://jeff.news/article/2433
---
# 음성 AI에 WebRTC 쓰지 말라는 꽤 빡센 반론

Twitch와 Discord에서 WebRTC SFU를 직접 구현했던 엔지니어가 OpenAI의 음성 AI용 WebRTC 아키텍처를 정면으로 비판한 글이다. 핵심은 WebRTC가 회의용 실시간 통화에는 맞지만, 프롬프트 정확도와 안정적인 스트리밍이 중요한 음성 AI에는 패킷 드롭, 복잡한 핸드셰이크, 로드밸런싱 문제를 만든다는 주장이다. 대안으로는 WebSocket부터 시작하고, 장기적으로는 QUIC/WebTransport 계열을 보라는 쪽에 가깝다.

- 글쓴이는 결론부터 세게 박음. 음성 AI에 WebRTC를 그대로 베끼지 말라는 것임
  - 본인은 Twitch에서 WebRTC SFU를 만들었고, Discord에서는 Rust로 WebRTC SFU를 다시 쓴 경험이 있음
  - WebRTC가 대략 45개 RFC와 여러 사실상 표준 초안(TWCC, REMB 등) 위에 얹힌 거대한 묶음이라, 직접 구현해본 입장에서는 다시 쓰고 싶지 않다는 톤임

- 핵심 비판은 “WebRTC는 회의용이지, 음성 AI용이 아니다”임
  - 회의에서는 오디오가 조금 깨져도 대화 턴이 빨리 오가는 게 중요함
  - 그런데 음성 AI에서는 사용자의 말이 곧 프롬프트라서, 200ms 더 기다리더라도 정확하게 들어가는 게 훨씬 중요함
  - 네트워크가 안 좋을 때 WebRTC가 오디오 패킷을 버리면, 사용자는 “세차장까지 걸어갈까 운전할까”라고 말했는데 모델은 엉뚱하게 들을 수 있음

> [!IMPORTANT]
> 음성 AI에서 오디오 패킷 드롭은 단순한 품질 저하가 아니라 프롬프트 손상임. 입력이 망가지면 LLM 응답도 같이 망가짐.

- WebRTC의 낮은 지연시간 최적화가 음성 AI의 제품 경험과 충돌한다는 지적이 꽤 날카로움
  - 브라우저 WebRTC 구현에서는 오디오 패킷 재전송이 사실상 어렵거나 제한적이라고 설명함
  - 일부 WebRTC 개발자들은 오디오 NACK 설정이 가능하다고 반박했지만, 글쓴이는 Discord에서도 SDP 설정을 제대로 풀지 못했고 jitter buffer도 공격적으로 작다고 덧붙임
  - 음성 에이전트가 언젠가 대화 수준의 지연시간까지 내려가더라도, 일부러 프롬프트 오디오를 희생하는 게 맞는지는 별개의 문제라는 얘기임

- TTS 출력 쪽에서도 WebRTC가 이상한 제약을 만든다고 봄
  - 예를 들어 GPU가 2초 동안 8초짜리 음성을 생성할 수 있다면, 이상적으로는 빠르게 내려받아 클라이언트가 8초 동안 재생하면서 버퍼를 가져가면 됨
  - 그런데 WebRTC는 도착 시간 기준으로 렌더링하고, 로컬 버퍼링을 풍부하게 가져가는 모델이 아님
  - 그래서 서버가 오디오 패킷 앞에 인위적인 sleep을 넣어 “재생 시점에 맞춰” 보내야 하고, 네트워크 혼잡이 생기면 그 패킷은 그냥 사라질 수 있음

- 글쓴이는 이 상황을 “유튜브 영상을 버퍼링하지 않고 화면 공유로 보는 것”에 비유함
  - TTS는 실시간보다 빠르게 생성될 수 있는데, WebRTC를 쓰면 굳이 실시간 도착 모델에 맞춰 품질을 깎는 셈이라는 것
  - WebRTC 자체도 오디오용 동적 jitter buffer 때문에 20ms에서 200ms 정도의 지연을 추가할 수 있음

## 포트와 로드밸런싱 문제가 진짜 골치임

- 일반 TCP 서버는 보통 443 같은 포트 하나를 열고, 클라이언트의 임시 포트와 함께 연결을 식별함
  - 문제는 모바일에서 Wi-Fi와 셀룰러를 오가거나 NAT가 소스 IP/포트를 바꾸면 연결이 끊긴다는 점임
  - TCP+TLS를 다시 잡으려면 최소 2-3 RTT가 들어가고, 라이브 스트리밍에서는 사용자가 바로 느끼는 끊김이 됨

- WebRTC는 이 문제를 풀려고 연결마다 서버 쪽 임시 포트를 할당하는 모델을 둠
  - 그러면 세션을 목적지 IP/포트만으로 식별할 수 있어 소스 IP/포트 변화에 강해짐
  - 하지만 대규모 서비스에서는 서버 포트 수가 제한적이고, 방화벽은 임시 포트를 싫어하고, Kubernetes 환경에서도 운영이 지저분해짐

- 그래서 현실의 대형 서비스들은 WebRTC 명세를 그대로 따르지 않고 우회함
  - Twitch는 WebRTC 서버를 UDP 443에서 돌려 방화벽 통과율을 높였다고 함
  - Discord는 CPU 코어별로 50000-50032 포트를 썼고, 그만큼 일부 기업망에서는 더 자주 막힐 수 있음
  - OpenAI도 단순한 명세 구현이 아니라 커스텀 로드밸런싱을 붙인 것으로 보임

- 더 까다로운 건 WebRTC가 사실 여러 프로토콜을 한 코트 안에 넣은 구조라는 점임
  - STUN은 ufrag로 라우팅할 수 있음
  - SRTP/SRTCP는 브라우저가 고른 임의의 SSRC로 대체로 라우팅 가능함
  - DTLS는 RFC9146 같은 확장이 널리 지원되길 바라야 하는 영역이고, TURN은 또 별도 난제임

- 글쓴이는 OpenAI가 STUN 헤더와 ufrag만 파싱하고 나머지 DTLS, RTP, RTCP는 opaque하게 넘기는 구조를 두고 “필요한 해킹”이라고 봄
  - 보기 좋게 말하면 프로토콜 종료 없이 릴레이하는 구조임
  - 거칠게 말하면 사용자의 소스 IP/포트가 바뀌지 않길 바라는 구조가 될 수 있다는 비판임
  - OpenAI 규모에서 이런 로드밸런싱을 만든 건 인상적이지만, 애초에 프로토콜이 문제라는 게 글의 논지임

```mermaid
sequenceDiagram
    participant 브라우저
    participant 릴레이
    participant 상태저장소
    participant 미디어서버
    브라우저->>릴레이: STUN 패킷과 ufrag 전송
    릴레이->>상태저장소: ufrag 또는 소스 주소 매핑 조회
    릴레이->>미디어서버: DTLS/RTP/RTCP 패킷 전달
    브라우저-->>릴레이: 네트워크 전환으로 소스 IP/포트 변경
    릴레이->>상태저장소: 기존 연결 매핑 재확인
    릴레이->>미디어서버: 같은 세션으로 라우팅 시도
```

## 연결 수립도 가볍지 않음

- OpenAI 글의 요구사항 중 하나가 “사용자가 세션 시작 후 바로 말할 수 있을 만큼 빠른 연결 설정”이었다고 함
  - 글쓴이는 여기서 웃고 넘어가지 않음. WebRTC 연결 수립에는 최소 8회 안팎의 RTT가 필요하다고 계산함
  - signaling 서버 쪽에서 TCP 1회, TLS 1.3 1회, HTTP 1회가 들어감
  - media 서버 쪽에서는 ICE 1회, DTLS 1.2 2회, SCTP 2회가 추가됨

- 이 복잡한 절차는 WebRTC가 P2P까지 지원해야 해서 생긴 비용임
  - 서버가 고정 IP를 갖고 있어도 이 춤을 춰야 함
  - signaling 서버와 media 서버가 같은 호스트나 프로세스에 있어도 중복 핸드셰이크를 하게 될 수 있음

- 글쓴이는 WebRTC를 포크하는 길도 결국 한계가 있다고 봄
  - 브라우저 구현은 Google이 주도하고 Google Meet에 최적화된 측면이 크다고 봄
  - 그래서 많은 회의 앱이 네이티브 앱 설치를 유도하는 이유도 WebRTC 제약을 피하려는 것이라고 설명함
  - Discord의 네이티브 클라이언트도 WebRTC 전체가 아니라 아주 일부만 구현하는 방향으로 강하게 포크됐지만, 웹 클라이언트 때문에 여전히 전체 프로토콜을 상대해야 함

## 대안은 WebSocket, 그리고 QUIC/WebTransport

- 당장 OpenAI에서 일한다면 글쓴이는 음성 스트리밍을 WebSocket으로 시작하겠다고 함
  - 기존 TCP/HTTP 인프라를 그대로 활용할 수 있음
  - Kubernetes와도 잘 맞고, 커스텀 WebRTC 로드밸런서를 새로 만드는 것보다 훨씬 단순함
  - head-of-line blocking도 음성 AI에서는 단점이 아니라 “정확한 순서와 입력 보존”이라는 사용자 경험일 수 있다고 봄

- 장기적으로 패킷 드롭이나 우선순위 제어가 필요해지면 WebTransport와 QUIC을 보라고 함
  - QUIC 연결 수립은 QUIC+TLS 기준 1 RTT로 끝남
  - WebRTC의 여러 단계 핸드셰이크와 비교하면 연결 시작부터 훨씬 단순함

- QUIC의 Connection ID는 이 글에서 거의 주인공처럼 등장함
  - QUIC은 소스 IP/포트 기반 라우팅을 버리고, 패킷 안에 0-20바이트 Connection ID를 넣을 수 있음
  - 이 ID는 수신자가 고르기 때문에 서버가 연결마다 유니크한 ID를 만들어줄 수 있음
  - 클라이언트가 Wi-Fi에서 셀룰러로 바뀌어 소스 주소가 달라져도, QUIC은 연결을 끊지 않고 새 주소로 이동할 수 있음

- QUIC-LB를 쓰면 로드밸런서의 상태 저장 문제도 줄어듦
  - OpenAI식 구조는 소스 IP/포트에서 백엔드 서버로 가는 매핑을 Redis 같은 저장소에 둘 수 있음
  - QUIC-LB는 백엔드 서버가 자기 ID를 Connection ID에 인코딩하게 해서, 이후 패킷은 그 ID만 보고 전달할 수 있음
  - 로드밸런서는 라우팅 테이블이나 암호화 키 없이 앞부분 몇 바이트를 해석해 해당 백엔드로 보내면 됨

> [!TIP]
> 음성 AI를 새로 설계한다면 “브라우저에서 되니까 WebRTC”로 바로 가기 전에 WebSocket, QUIC, WebTransport를 요구사항별로 비교해볼 만함. 특히 프롬프트 정확도와 모바일 네트워크 전환이 중요하면 기본값이 달라질 수 있음.

- anycast와 unicast 조합도 QUIC에서 더 멋지게 풀 수 있다고 설명함
  - 수천 대의 백엔드가 같은 anycast 주소를 광고하고, 클라이언트는 그 주소로 첫 QUIC 핸드셰이크를 보냄
  - 서버는 연결을 맺으면서 preferred_address로 자기 고유 unicast 주소를 알려줌
  - 이후 클라이언트는 stateful 연결을 unicast로 보내고, 서버가 과부하 상태면 anycast 광고만 중단하면 됨
  - 기존 연결은 unicast에 남아 있으니 새 연결 유입만 줄이고 기존 세션은 유지할 수 있다는 아이디어임

- 글의 마지막은 꽤 공정함. OpenAI 엔지니어들이 똑똑하고 엄청난 압박 속에서 스케일을 맞춰야 한다는 점은 인정함
  - 다만 “명백해 보이는 솔루션”인 WebRTC가 음성 AI에는 좋은 제품 핏이 아닐 수 있다는 주장임
  - MoQ도 음성 AI에 완벽한 답은 아니고, 캐시나 fanout 의미론은 1:1 오디오에 별로 쓸모없을 수 있다고 덧붙임
  - 그래도 QUIC은 쓰라는 결론은 끝까지 유지함

---

## 기술 맥락

- 여기서 중요한 건 WebRTC가 나쁜 기술이라는 얘기가 아니에요. WebRTC는 회의처럼 사람끼리 바로 치고받는 상황을 위해 만들어졌기 때문에, 조금 깨져도 빨리 들리는 쪽을 택해요. 그런데 음성 AI에서는 사용자의 말이 모델 입력이라서, 빨리 들어가는 것보다 제대로 들어가는 게 더 중요해져요.

- OpenAI 같은 서비스가 WebRTC를 고르면 브라우저 지원이라는 큰 장점은 얻어요. 대신 ICE, DTLS, SCTP, RTP, STUN 같은 구성요소를 대규모로 운영해야 하고, 연결 수립과 로드밸런싱도 같이 복잡해져요. 글쓴이가 문제 삼는 지점은 바로 이 운영 비용이에요.

- QUIC이 매력적으로 보이는 이유는 Connection ID 때문이에요. 모바일 사용자의 IP나 포트가 바뀌어도 연결을 식별할 수 있고, QUIC-LB를 쓰면 백엔드 서버 정보를 Connection ID에 넣어 상태 저장소 없이 패킷을 보낼 수 있거든요.

- WebSocket을 먼저 쓰자는 제안도 “구식이라서 쉬운 선택”이 아니에요. 음성 AI의 초기 제품에서는 순서 보장과 기존 인프라 호환성이 더 중요할 수 있고, 나중에 스트림별 우선순위나 일부 데이터그램 처리가 필요해질 때 WebTransport로 넘어가는 전략이 더 현실적이라는 뜻이에요.

## 핵심 포인트

- WebRTC는 낮은 지연시간을 위해 오디오 패킷을 공격적으로 버리는데, 음성 AI에서는 프롬프트 정확도를 망칠 수 있다
- WebRTC 연결 수립에는 최소 8회 안팎의 RTT가 필요하고, P2P 지원을 위한 복잡한 절차가 서버 기반 음성 AI에도 그대로 붙는다
- 대규모 서비스는 WebRTC 명세대로 포트를 연결마다 열기 어렵기 때문에 결국 UDP 단일 포트, STUN ufrag 라우팅 같은 해킹에 가까운 우회가 필요해진다
- QUIC은 Connection ID와 QUIC-LB 덕분에 소스 IP/포트 변화, 상태 없는 로드밸런싱, anycast/unicast 전환을 더 깔끔하게 다룰 수 있다

## 인사이트

이 글의 포인트는 “OpenAI가 틀렸다”보다 “회의용 프로토콜을 음성 AI에 그대로 가져오면 제품 요구사항이랑 충돌한다”에 가깝다. 실시간 미디어를 다루는 팀이라면 WebRTC가 기본값처럼 보일 때 한 번쯤 의심해볼 만한 글이다.
