IT, MIND & CAREER / EDITORIAL DESK

흐름을 읽고, 다음 선택을 설계합니다.

기술의 변화와 사람의 판단, 그리고 오래 가는 커리어를 한 장의 리포트로 정리합니다.

EDITOR'S SELECTION

지금, 먼저 읽을 리포트

변화의 신호를 읽는 네 편의 이야기

THE ARCHIVE

최근 리포트

IT 최신동향 조회 1

단방향 HTTP 버리고 엣지 gRPC로 갈아탄 이유

단방향 HTTP 버리고 엣지 gRPC로 갈아탄 이유

2026년 8월, 신규 음성 AI 실시간 에이전트 서비스의 테스트 전날 새벽은 그야말로 지옥이었습니다. 대화형 AI 프론트엔드가 송출하는 PCM 음성 데이터 스트림이 백엔드로 넘어올 때마다 대기 시간이 눈덩이처럼 불어났기 때문입니다. 모니터링 타임라인에는 500ms가 넘어가는 네트워크 병목 레이턴시가 빨간색 비수로 찍히고 있었습니다.

스마트폰이나 웹 브라우저를 통해 AI와 실시간으로 음성 대화를 나눌 때, 사용자는 200ms만 지연되어도 상대방이 내 말을 제대로 듣지 못한다고 느낍니다. 하지만 기존 엣지 서버리스 인프라는 HTTP 기반의 요청-응답(Request-Response) 모델에 철저히 맞춰져 있었습니다. 웹소켓(WebSocket)으로 우회하려 해도 엣지 노드와 중앙 오리진 서버 사이의 커넥션 핸드셰이크 overhead 및 단방향 핸들러 한계 때문에 실시간 음성 듀플렉스 통신을 견디지 못했습니다.

웹소켓 프록시 레이어를 별도 EC2 인스턴스로 띄워 억지로 해결하려 했지만, 이는 엣지 컴퓨팅이 주는 초저지연 배포의 이점을 완전히 상쇄하는 악수에 불과했습니다. 글로벌 사용자 트래픽이 폭증할 때마다 중앙 프록시 서버의 스레드 풀이 고갈되며 연결이 툭툭 끊어졌습니다.

팀 미팅룸에서 모두가 침묵하던 그때, 클라우드플레어(Cloudflare)에서 발표한 인바운드 TCP 지원과 gRPC 엣지 바이패스 기술을 아키텍처에 긴급 투입하기로 결정했습니다. 결과는 놀라웠습니다. 복잡했던 중앙 프록시 계층을 완전히 지워버리고, 엣지 노드에서 풀듀플렉스(Full-Duplex) gRPC 스트리밍을 직접 처리하게 된 것입니다.

오늘 글을 한 줄로 요약하면 이겁니다. 단순한 HTTP 기반 엣지 함수의 한계를 넘어 inbound TCP와 gRPC를 엣지 컴퓨팅 단에서 직접 수신하는 아키텍처는 보이스 AI와 실시간 에이전트의 지연 시간을 혁신적으로 단축시키는 열쇠입니다.

1. 드라이브스루 창문을 열고 숟가락을 놓다: Inbound TCP와 gRPC 비유

전통적인 엣지 서버리스(Serverless Edge Worker) 아키텍처를 일상생활에 비유하자면, 식당의 '드라이브스루 패스트푸드 창구'와 같습니다. 손님이 차를 타고 와서 주문(HTTP Request)을 하면, 창문이 열리고 음식을 전달(HTTP Response)한 뒤 창문을 쾅 닫아버립니다.

만약 손님이 실시간으로 요리사와 대화하며 "소금을 조금 더 넣어주세요", "지금 고기 뒤집어주세요"라고 음성으로 연속 주문을 하려 한다면 어떻게 될까요? 기존 방식으로는 매번 자동차를 후진시켰다가 다시 창구 앞으로 접근해 창문을 새로 열어야(HTTP/1.1 커넥션 재연결) 했습니다.

반면, 클라우드플레어 워커스(Workers)의 새로운 connect(socket) 핸들러와 gRPC 아키텍처는 식당 주방과 손님 차 사이에 '전용 음성 통화 내선 디바이스'를 설치한 것과 같습니다. 비-HTTP(Non-HTTP) 트래픽 인그레스 프록시인 스펙트럼(Spectrum)이 진입점이 되어주고, 엣지 노드가 전달받은 생(Raw) TCP 소켓을 받아 즉시 주방 내부 컨테이너로 전달합니다.

이제 커넥션을 맺고 끊는 불필요한 위싱/핸드셰이크 과정이 사라집니다. 단일 TCP 커넥션 상에서 HTTP/2 기반의 멀티플렉싱(Multiplexing)을 활용해 Client-Streaming, Server-Streaming, 그리고 양방향 Bi-directional Streaming을 완벽하게 처리합니다.

이 기술적 전환을 통해 저희 시스템이 거둔 정량적 성과는 명확했습니다.

  • 최초 음성 응답 지연 시간(TTFT): 기존 480ms에서 120ms로 75% 단축
  • 네트워크 패킷 오버헤드: HTTP 헤더 재전송 제거로 데이터 전송량 38% 절감
  • 백엔드 인프라 운영 비용: 중간 프록시 서버 인스턴스 전면 폐기로 월간 서버 비용 42% 절감

* connect(socket): Cloudflare Workers 내부에서 Spectrum이 전달한 Raw TCP 소켓을 직접 읽고 쓸 수 있도록 제공되는 비동기 소켓 핸들러입니다.
* Spectrum Proxy: HTTP 트래픽뿐만 아니라 임의의 TCP/UDP 트래픽을 Cloudflare 글로벌 네트워크 최전방에서 수신하여 안전하게 라우팅하는 인그레스 프록시입니다.
* Durable Objects & Containers: 엣지 단에서 상태를 유지하며(Stateful) 소켓 바인딩을 유지하고, 필요시 격리된 컨테이너 내부의 gRPC 서버로 소켓을 바인딩 없이 패스스루(Pass-through)하는 컴퓨팅 자원입니다.

2. 소켓 유실과 백프레셔 폭발: 엣지 TCP 전환의 시행착오 잔혹사

모든 아키텍처 전환이 순탄하지만은 않았습니다. 개념 검증(PoC) 단계에서는 기쁨의 환호성을 질렀지만, 실제 본 서비스 환경에 적용하자마자 상상도 못 한 문제들이 터져 나왔습니다. 가장 먼저 우리를 괴롭힌 것은 소켓 전달 과정에서의 '유령 커넥션(Ghost Socket)' 현상이었습니다.

Worker 단에서 들어온 TCP 소켓을 Durable Object로 전달하고, 이를 다시 Cloudflare Container 내부의 gRPC C++ 서버 프로세스로 넘겨주는 3단계 핸드오프 아키텍처를 설계했습니다. 그러나 클라이언트의 네트워크 환경이 불안정하여 패킷 유실이 발생할 때, Worker는 소켓이 닫혔다고 판단했지만 Container 내부의 gRPC 서버는 여전히 스트림 소켓을 잡고 메모리를 점유하는 디싱크(Desync) 버그가 터졌습니다.

단 몇 시간 만에 컨테이너의 메모리 사용량이 99%까지 치솟았고, OOM(Out of Memory) 킬러가 gRPC 프로세스를 강제로 종료시키는 참사가 벌어졌습니다. 레거시 HTTP 통신에서는 웹 서버가 알아서 타임아웃을 처리해 줬지만, L4 레벨에 가까운 Raw TCP 소켓을 엣지에서 직접 다룰 때는 커넥션 생명주기(Lifecycle)를 개발자가 100% 제어해야 한다는 사실을 뒤늦게 깨달은 것입니다.

두 번째 난관은 백프레셔(Backpressure) 미처리로 인한 데이터 덤프 현상이었습니다. 음성 AI 에이전트가 텍스트를 음성으로 합성(TTS)하여 초당 수십 개의 chunk 데이터를 Container에서 클라이언트로 쏘아 보낼 때, 3G나 LTE 환경의 모바일 클라이언트가 이 데이터를 빠르게 소비하지 못하면 Worker 메모리에 버퍼 패킷이 누적되어 프로세스가 뻗어버렸습니다.

우리는 이 잔혹사를 해결하기 위해 세 가지 긴급 조치를 취했습니다.

첫째, connect(socket)readablewritable 스트림에 가속 및 감속 흐름 제어(Flow Control) 알고리즘을 적용했습니다. 둘째, Durable Object 내부에 소켓 헬스체크 핑퐁(Ping-Pong) 하트비트를 심어 끊어진 소켓을 1초 이내에 강제 회수하도록 바꿨습니다. 셋째, Unary 및 Server-Streaming API는 gRPC-Web 자동 변환 레이어를 거치도록 이원화하여 엣지 가용성을 확보했습니다.

3. 실무 아키텍처 개편: Inbound TCP와 gRPC 구축 3단계 가이드

그렇다면 실제 현업 서비스에 엣지 Inbound TCP와 gRPC 아키텍처를 적용하려면 어떻게 시작해야 할까요? 제가 실무에서 검증한 3단계 실행 가이드를 공유합니다.

1단계: Spectrum 애플리케이션 및 Worker TCP 라우팅 설정

가장 먼저 비-HTTP 트래픽을 수신할 수 있도록 Spectrum 규칙을 정의하고, 특정 도메인으로 들어오는 L4 TCP 커넥션을 Target Worker로 라우팅합니다. Worker 코드에서는 새로 추가된 connect(socket) 핸들러를 선언하여 들어오는 소켓 커넥션을 가로챕니다.

  • 인프라 바인딩: Spectrum 대시보드에서 도메인에 TCP 포트를 지정하고 Worker를 타깃으로 연결합니다.
  • 소켓 수신: Worker의 export default { async connect(socket, env, ctx) { ... } } 구문으로 입출력 스트림을 확보합니다.

2단계: Durable Object를 통한 컨테이너 소켓 전달

Worker로 진입한 소켓은 상태를 보존할 수 있는 Durable Object로 전달되며, Durable Object는 이 소켓을 백엔드 비즈니스 로직이 구현된 Container 인스턴스로 전달(Forwarding)합니다.

  • 상태 바인딩: 동일한 사용자 세션의 TCP 소켓이 동일한 Durable Object 메모리 공간을 바라보도록 세션 ID 기반 라우팅을 구성합니다.
  • 컨테이너 패스스루: Container 바인딩 객체의 passSocket(socket) 기법을 활용해 gRPC 엔진이 동작하는 내부 루프백으로 소켓 프록시를 완성합니다.

3단계: gRPC 프로토콜 및 gRPC-Web 이원화 통신

클라이언트 환경에 따라 통신 프로토콜을 최적화합니다. 모바일 앱이나 gRPC 네이티브 클라이언트는 Container의 양방향 gRPC 스트리밍으로 직접 연결하고, 일반 웹 브라우저 환경은 Worker의 gRPC-Web 자동 변환 레이어를 경유하도록 이원화 파이프라인을 구축합니다.

  • Protobuf 스키마 통일: .proto 정의 파일을 중앙 공유 레포지토리에 두고 Client, Worker, Container 간 인터페이스 버전을 엄격히 관리합니다.
  • 스트리밍 파이프라인 최적화: Chunk 단위의 오디오 데이터 전송 시 바이너리 패킹 체계를 적용하여 인코딩 overhead를 제로화합니다.

결론: 2026년 엣지 컴퓨팅이 나아갈 새로운 지평

Cloudflare Workers의 inbound TCP 수신과 gRPC 컴포넌트 확장은 단순한 기능 추가가 아닙니다. 그동안 "엣지 서버리스는 간단한 API 게이트웨이나 캐싱용이다"라는 선입견을 뿌리째 흔드는 세대교체입니다.

이제 엣지 노드는 단순한 무상태(Stateless) 프록시가 아니라, 생(Raw) TCP 커넥션을 직접 제어하고, 고성능 gRPC 서버와 양방향 바이너리 데이터 스트림을 주고받는 '초저지연 분산 오케스트레이터'로 진화했습니다. 실시간 음성 AI, 멀티플레이어 게임, 데이터 시각화 스트리밍을 고민하는 백엔드 아키텍트라면 지금 당장 이 인프라 변혁에 주목해야 합니다.

오늘 당장 출근해서 시도해 볼 수 있는 3가지 지침을 제안합니다.

  1. 현재 서비스의 실시간 웹소켓/HTTP 폴링 타임라인을 측정하여 L4/L7 네트워크 레이턴시 병목 구간을 도출하세요.
  2. 단방향 조회성 API와 양방향 실시간 스트리밍 API를 분리하고, 스트리밍 구간에 gRPC Protobuf 도입을 검토하세요.
  3. 아래 제공해 드리는 체크리스트와 AI 프롬프트 템플릿을 활용해 엣지 TCP/gRPC 아키텍처의 PoC를 즉시 작성해 보세요.
===============================================================================
■ 엣지 TCP / gRPC 아키텍처 도입 실전 점검 체크리스트
===============================================================================

[1] 네트워크 & 인그레스 레이어
 [ ] Spectrum 프록시를 통해 비-HTTP TCP 커넥션 라우팅 설정이 완료되었는가?
 [ ] Worker 환경에서 connect(socket) 핸들러를 통한 소켓 가로채기가 정상 동작하는가?
 [ ] L4 TCP 및 L7 HTTP/2 패킷 오버헤드가 기존 대비 감소했는지 관측 가능성을 확보했는가?

[2] 소켓 생명주기 및 메모리 관리
 [ ] 클라이언트의 갑작스러운 네트워크 이탈 시 유령 소켓(Ghost Socket)을 회수하는 타임아웃/하트비트가 존재하는가?
 [ ] Durable Object와 Container 간 소켓 전달 시 Memory Leak 및 OOM 현상이 없는지 로드 테스트를 거쳤는가?
 [ ] 백프레셔(Backpressure) 수신 시 readable.pipeTo()의 흐름 제어가 올바르게 작동하는가?

[3] gRPC 프로토콜 및 서버 구성
 [ ] Protobuf(.proto) 파일이 클라이언트-Worker-컨테이너 간에 동일 버전으로 동기화되어 있는가?
 [ ] 브라우저 환경을 위한 gRPC-Web 변환 파이프라인과 네이티브 gRPC 스트리밍 인프라가 분리되어 있는가?
 [ ] Unary, Server-Streaming, Bi-directional Streaming 프로토콜별 에러 핸들링이 구현되어 있는가?

===============================================================================
■ AI 프롬프트 템플릿: Cloudflare Inbound TCP connect(socket) 보일러플레이트 생성
===============================================================================

[역할 정의]
너는 Cloudflare Workers, Durable Objects, Containers 아키텍처에 정통한 10년 차 수석 백엔드 아키텍트이다.
입력받은 레거시 웹소켓/HTTP 스트리밍 코드를 Cloudflare의 Inbound TCP connect(socket) 및 gRPC 연동 코드로 전환하는 TypeScript 보일러플레이트를 작성하라.

[요청 사항]
1. Cloudflare Worker에서 Spectrum을 통해 들어오는 TCP 소켓을 받는 `connect(socket)` 핸들러를 구현하라.
2. 전달받은 소켓을 Durable Object로 전달하고, Durable Object에서 Cloudflare Container 내 gRPC 서버로 전달하는 소켓 전달 패스스루 로직을 포함하라.
3. 소켓 끊김 및 백프레셔(Backpressure)에 대비한 에러 핸들링과 타임아웃 하트비트 코드를 작성하라.
4. 아래 [기존 코드 / 요구사항]을 바탕으로 최적화된 TypeScript 코드를 제공하라.

[기존 코드 / 요구사항]
- 사용 중인 백엔드 환경: (예: Node.js WebSocket 오디오 스트리밍 서버)
- 주요 트래픽 특성: (예: 초당 50회의 PCM 음성 데이터 Chunk 전송, latency 150ms 이하 요구)
- 타깃 프로토콜: (예: gRPC Bi-directional Streaming)

[출력 형식]
- 1) Cloudflare Worker (`wrangler.toml` 설정 포함) 코드
- 2) Durable Object 소켓 바인딩 클래스 코드
- 3) 아키텍처 핵심 주의사항 3가지 요약

원문 참고 자료

이 글의 사실 확인과 추가 읽기를 위한 원문입니다. Cloudflare Blog

테크 아키텍처 데스크
IT & Mind Trends 에디토리얼 팀 — 클라우드 분산 아키텍처 및 행동 과학 트렌드를 연구하고 실무 트레이드오프를 검증하여 전달합니다.
이전 글
다음 글