TrotVote
[IT 심층 분석]

4K 60fps 비디오 스트리밍 환경에서 버퍼 언더런 현상을 잠재우는 TCP 스택과 소켓 튜닝

김민준 · IT 시스템 엔지니어|
고스펙 웨어러블 카메라로 촬영한 4K 60fps 영상을 이더넷도 아닌 무선 랜이나 5G 통신을 거쳐 클라우드 인제스트(Ingest) 서버로 실시간 스트리밍 하는 프로젝트는 네트워크 지연 대기시간의 한계를 넘나드는 지독한 도전이었습니다. 스트리밍 프로토콜로 RTMP 대신 레이턴시가 더 낮은 SRT나 WebRTC를 도입했음에도 불구하고 필드 테스트에서 수신 서버 측의 영상 재생기가 툭툭 끊기며 픽셀 스미어링 현상이 발생하는 버퍼 언더런 장애가 수시로 튀어나왔습니다. 네트워크 인프라 담당자와 시스템 엔지니어 모두가 핑과 대역폭을 체크하며 한 치의 물러섬도 없는 원인 규명 공방전이 벌어졌죠. 대역폭은 분명히 충분한데 왜 데이터는 말라붙어 클라이언트 디스플레이에 끔찍한 모자이크 블록을 흩뿌리는 것일까요. 사태의 본질은 네트워크 환경의 대역폭 한계가 아니라 전송 계층인 TCP 스택 내부의 혼잡 제어(Congestion Control) 메커니즘과 운영체제의 소켓 송신 버퍼 사이의 끔찍한 불화에서 기인한 것이었습니다. 리눅스 서버에 Wireshark와 tcpdump 도구를 동원해 패킷 전송 시퀀스를 수 시간동안 녹화해보았더니 굉장히 특이한 이빨 빠짐 현상을 목격했습니다. 클라이언트가 패킷 로스로 인해 지연 확인응답(Delayed ACK)을 보내는 찰나 서버의 리눅스 커널은 기본 설정된 TCP CUBIC 혼잡 제어 알고리즘의 보수성 때문에 송신 윈도우 사이즈를 무자비하게 절반으로 칼질해버린 것이었습니다. 네트워크 파이프라인의 혈관이 갑작스레 좁아지니 카메라 측의 인코더는 초당 수십 메가바이트의 4K 빅샷 데이터를 쏟아내는데 커널의 소켓 센드 버퍼에 이것들이 정체하게 되었고 그 오버플로우된 프레임들은 미련 없이 드랍되고 있었죠. 결과적으로 수신 측 디코더에는 구멍 뚫린 비트스트림이 도착해 치명적인 버퍼 언더런 파편화가 발생한 것입니다. 이 난제를 분쇄하기 위해 커널 수준의 네트워크 프로파일 수술에 즉시 돌입했습니다. 첫 번째 솔루션으로 낡고 느긋한 반응성을 자랑하는 기본 CUBIC 혼잡 제어 알고리즘을 폐기하고 구글이 개발한 통신 왕조격 알고리즘인 BBR(Bottleneck Bandwidth and Round-trip propagation time) 제어 모델을 도입하여 sysctl 환경을 강제로 패치했습니다. 패킷 손실이라는 단일 지표에 맹목적으로 의존해 윈도우를 토막 내는 과거의 방식과 달리 BBR은 패킷의 실제 왕복 시간 딜레이와 측정된 병목 대역폭을 똑똑하게 수식으로 산정하여 스스로 페이싱(Pacing)을 통해 전송 속도를 매끄럽게 조절했습니다. 그 결과 혼란스러운 무선 환경에서도 송신 윈도우가 급격히 요동치지 않고 안정적으로 데이터의 혈류량을 담보해낼 수 있게 되었습니다. 두 번째로는 커널 파라미터의 버퍼 수용량을 폭증시켰습니다. 4K 해상도의 키 프레임 즉 I-frame 하나당 페이로드 크기는 순간적으로 끔찍하게 비대해지는데 기존의 기본 TCP 송수신 버퍼 크기인 tcp_rmem과 tcp_wmem 세팅은 이 거대한 튀어오름을 감당하기에 역부족이었습니다. 최대 16MB 영역까지 커널 메모리를 역동적으로 확장하여 사용할 수 있도록 BDP(Bandwidth-Delay Product)의 공식을 거꾸로 치환해 최적화 값들을 강제 주입했습니다. 추가적으로 NIC 하드웨어 큐 계층에서 qdisc를 기존의 pfifo_fast에서 완전 공정 큐잉 기법인 fq(Fair Queuing)로 전환하여 패킷 버스트(Burst) 조차 매끄럽게 깎아냈습니다. 이 모든 지독한 커널 레벨 네트워크 튜닝을 집대성하자 클라우드 엔드포인트에 떨어지는 영상 비트스트림은 그 어떠한 드랍 스파이크 현상 없이 부드러운 초당 60프레임의 강물이 되어 화면에 유유히 뿌려지게 되었습니다.