[SFU 딥다이브] SFU는 영상을 섞지 않고 중계한다
SFU를 처음 공부할 때 가장 헷갈렸던 단어는 미디어 서버였다. 서버가 가운데 있으니 당연히 모든 영상을 받아 새 화면으로 만들어 준다고 생각했다. 그런데 SFU를 따라가 보니 핵심은 합성이 아니라 선택이었다. 같은 입력인데 어떤 환경에서만 SFU가 도드라졌다. 그래서 용어 사전 대신, 그 날 무엇을 보고 무엇을 바꿨는지부터 적는다.

SFU가 필요해진 지점
SFU를 붙인 뒤에도 제품 질문은 남는다. 어떤 subscriber에게 어떤 layer를 보냈는지, 그 선택이 네트워크 때문인지 화면 크기 때문인지, 서버 region 때문인지 알 수 있어야 한다. 앱 로그에는 방 상태와 사용자 행동이 남고, 미디어 서버 로그에는 publisher, subscriber, bitrate, packet loss, selected layer가 남는다. 두 로그가 다른 이름을 쓰면 장애 회고는 다시 감으로 돌아간다. | 요소 | SFU가 보는 것 | 제품에서 정해야 할 경계 | |---|---|---| | publisher | 업로드 stream, RTP 흐름, simulcast/SVC 후보 | 어떤 품질 후보를 올릴지, 화면 공유와 카메라를 어떻게 구분할지 | | subscriber | 구독 목록, 수신 품질, 네트워크 추정 | 누구의 화면을 우선할지, 낮은 품질 전환을 어떻게 알릴지 | | layer | 해상도, bitrate, frame rate 같은 선택 단위 | 작은 타일과 주 화면에 다른 기준을 둘지 | | SFU | forwarding 정책, 방 권한, egress, region | 로그와 과금, 내가 SFU를 제품 경계로 볼 때 먼저 붙이는 실패 이름은 네 가지다.
첫째, 품질 후보가 부족해서 선택할 수 없는 상태다. simulcast나 SVC 전략이 없으면 SFU는 subscriber별로 다른 품질을 고르기 어렵다. 둘째, forwarding 정책은 있는데 사용자 문구가 없는 상태다. 이때 사용자는 왜 화질이 내려갔는지 모른다. 이 관찰 기준이 없으면 SFU는 곧 ‘서버 비용이 드는 Mesh 대체재’처럼만 보인다. 실제로는 방 정책, layer 선택, region 배치, 로그 이름이 함께 움직일 때 의미가 생긴다.
그래서 SFU 도입 여부는 미디어 서버를 띄울 수 있는지보다 선택을 설명할 준비가 되었는지로 판단해야 한다.

현재 구성의 가정
에서 이어진다. 그 글이 네 구조의 위치를 잡는 허브라면, SFU 내부의 선택 전달을 좁게 본다.에서 fan-out과 확장성을 다시 계산한다. 여기서 중요한 말은 선택이다. 모든 subscriber가 같은 품질을 받아야 하는 것은 아니다. 발표자의 화면 공유는 높은 해상도로 받고, 작은 썸네일 영상은 낮은 layer만 받을 수 있다. 모바일 사용자는 낮은 bitrate를 받고, 유선 환경의 데스크톱은 더 높은 품질을 받을 수 있다.
SFU는 이런 차이를 수신자 단위로 다룬다. 이 차이를 “SFU가 더 확장된다”로만 말하면 반쪽 설명이 된다. SFU는 비용을 없애는 장치가 아니라 비용의 위치를 바꾸는 장치다. 클라이언트 업로드, 서버 egress, 미디어 서버 region, packet loss 처리, layer 선택 정책이 함께 움직인다. 작은 방에서는 체감이 작아도 큰 방이나 장시간 세션에서는 운영 비용으로 돌아온다. PonsWarp에서 WebRTC가 길만 열어준다는 글은 이 경계를 다른 각도에서 보여 준다.
[을 같이 보면 signaling과 payload 책임을 분리해 볼 수 있다. [은 파일 전송에서 backpressure와 중단 후 복구를 더 잘 드러낸다. 미디어 SFU와 파일 전송 relay/storage 전략을 같은 답으로 밀어 넣지 않기 위해서도 두 글을 따로 보는 편이 낫다. 이 실패 이름은 화면 문장으로 내려와야 한다. 예를 들어 내부 로그에는 subscriber_layer_downgraded, sfu_region_switch_attempted, egress_limit_near 같은 값이 남을 수 있다. 화면에는 “상대 네트워크에 맞춰 화질을 낮췄습니다”, “가까운 경로로 다시 연결하는 중입니다”처럼 행동 가능한 문장이 필요하다.
개발자 로그와 사용자 문구는 다르지만 같은 상태 전이를 가리켜야 한다.

가정을 깨는 사례
내가 구현 전에 남겨 둘 체크리스트는 길지 않다. 대신 각 항목이 실제 화면 문구나 로그 필드로 이어져야 한다. SFU 구현을 시작하기 전에 기술 선택과 제품 문구를 함께 확인하기 위한 메모다. 특히 SFU에서는 재현 조건을 같이 적어야 의미가 있었다. SFU의 운영 로그는 미디어 서버 안에만 있으면 부족하다. 앱 로그와 연결되어야 한다. 사용자가 “상대 영상이 흐려졌습니다”라는 상태를 봤다면 같은 시각에 어떤 layer가 선택됐는지, 왜 내려갔는지, 다시 올라갔는지 확인할 수 있어야 한다.
이 연결이 없으면 SFU는 잘 동작해도 제품은 설명하지 못한다. SFU의 장점은 클라이언트 업로드 부담을 낮춘다는 데 있다. 10명 방에서 각 참여자가 모든 사람에게 직접 보내는 구조라면 업로드 경로가 빠르게 늘어난다. SFU 구조에서는 publisher가 서버로 한 번 올리고, 서버가 여러 subscriber에게 전달한다. 클라이언트 쪽 부담은 줄어들지만 서버 egress는 커진다. 이 체크리스트가 필요한 이유는 SFU가 성공 화면을 빨리 보여 주기 때문이다.
좋은 네트워크의 작은 방에서는 publisher, SFU, subscriber가 모두 자연스럽게 이어진다. 하지만 운영에서는 낮은 layer로 내려간 이유, region 선택이 늦어진 이유, 서버 egress가 튄 이유를 설명해야 한다. 그 설명은 나중에 덧붙이는 문구가 아니라 설계 초기에 남겨야 하는 경계다. SFU의 선택 단위를 publisher, subscriber, layer, 서버 책임으로 나눠 본 메모다. SFU를 설명할 때 서버/클라이언트/사용자 중 누구 문장으로 말하는지 먼저 고르면 논쟁이 줄었다.
분리·중계·직접연결 선택
SFU는 이 정보를 모두 완벽히 아는 존재가 아니다. 서버는 RTP 흐름, 수신자 상태, 네트워크 추정, 방 정책, 권한 정보를 바탕으로 전달 결정을 내린다. 브라우저는 실제 렌더링 상태와 사용자 행동을 더 잘 안다. 그래서 SFU 설계는 서버만 똑똑하게 만드는 문제가 아니라 서버와 클라이언트가 어떤 신호를 주고받을지 정하는 문제다. 셋째, 서버 비용이 늦게 드러나는 상태다.
테스트 방에서는 문제없어 보였지만 실제 사용에서 egress가 커지면 운영 비용이 제품 정책을 압박한다. 넷째, region과 latency가 한 덩어리로 기록되는 상태다. 어느 지역의 어떤 경로에서 늦어졌는지 모르면 다음 배포에서 고칠 지점도 흐려진다. 특히 SFU에서는 재현 조건을 같이 적어야 의미가 있었다. subscriber는 단순 소비자가 아니다. 화면 크기, 네트워크 상태, 디코딩 여력, 현재 보고 있는 UI가 모두 선택에 영향을 준다.
격자 화면에서 작은 타일로 보는 참여자에게 원본 화질을 계속 보내는 것은 낭비일 수 있다. 반대로 발표자 화면이나 녹화 대상 stream은 더 높은 품질이 필요할 수 있다. 서버는 무엇을 새로 만들고, 무엇을 그대로 넘기는가. 이 질문을 먼저 세우면 SFU와 MCU의 경계가 훨씬 선명해진다. SFU는 Selective Forwarding Unit이다. 대체로 publisher가 보낸 RTP 패킷이나 선택된 stream, 품질 layer를 받아 subscriber에게 전달한다.
모든 영상을 디코딩해서 하나의 장면으로 합성하는 MCU와는 출발점이 다르다.
다시 짜 본 구조
사용자 문구도 같은 기준으로 나눠야 한다. “연결 실패” 하나로 덮지 말고, “상대의 네트워크에 맞춰 화질을 낮추는 중”, “가까운 미디어 서버로 연결을 조정하는 중”, “발표자 화면을 우선 전달하는 중”처럼 선택 전달의 결과를 행동 가능한 말로 바꾼다. SFU의 장점은 서버를 가운데 두는 것 자체가 아니라, 가운데에서 내린 선택을 관찰하고 설명할 수 있다는 데 있다.
publisher는 하나의 영상만 올릴 수도 있고 여러 인코딩을 동시에 올릴 수도 있다. simulcast는 같은 콘텐츠를 서로 다른 품질의 여러 RTP stream으로 보내는 방식이다. SVC는 하나의 인코딩 안에 기본 layer와 향상 layer를 쌓아 두는 방식으로 이해하면 된다. 실제 구현 세부는 코덱과 브라우저 지원에 따라 달라지지만, 제품 판단에서는 “수신자별로 다른 품질을 고를 재료를 미리 보낼 것인가”가 핵심이다.
region도 같은 맥락이다. 모든 참여자가 같은 지역에 있으면 단순한 구성이 충분할 수 있다. 참여자가 여러 지역으로 흩어지면 가까운 SFU를 고를지, region 간 relay를 둘지, 특정 방을 한 지역에 고정할지 결정해야 한다. 평균 지연만 보면 놓치는 꼬리 구간이 생긴다. 회의에서 한 명의 발표자가 2초 늦게 들리는 문제는 평균값으로 가려지기 쉽다. 이 차이를 놓치면 SFU와 MCU가 같은 상자처럼 보인다.
MCU는 여러 입력을 디코딩하고, 레이아웃을 만들고, 다시 인코딩해서 하나의 출력으로 보낼 수 있다. 반면 SFU는 수신자별 선택을 통해 전달량과 품질을 조절한다. 그래서 서버 CPU, 클라이언트 CPU, 서버 egress, 지연의 위치가 달라진다. *SFU에서 숨기 쉬운 실패를 사용자 상태와 운영 로그로 나눠 본 지도다. '[SFU 딥다이브 SFU는 영상을 섞지 않고 중계한다'을 관통하는 질문은 이 섹션에서도 같았고, 답만 더 구체적이 됐다.
SFU의 실패 모드
마지막으로 남는 질문은 단순하다. 지금 서버가 맡는 일은 합성인가, 선택인가. 그리고 그 선택을 사용자가 기다릴 때 알아들을 수 있는 문장과 운영자가 추적할 수 있는 로그로 남겼는가. 이 두 질문에 답할 수 있을 때 SFU는 개념 설명을 지나 제품 설계의 도구가 된다. SFU를 “미디어를 합성하는 서버”가 아니라 “선택해서 전달하는 중계 지점”으로 다시 그린 흐름이다. 특히 SFU에서는 재현 조건을 같이 적어야 의미가 있었다.
이 표는 비교표라기보다 설계 메모에 가깝다. SFU를 켠다는 말은 네 요소의 경계를 정한다는 뜻이다. 어떤 정보는 서버에 남기고, 어떤 정보는 클라이언트가 보고하고, 어떤 제한은 사용자 문장으로 바꿔야 한다. 특히 SFU에서는 재현 조건을 같이 적어야 의미가 있었다. SFU를 손으로 그릴 때는 네 단어를 먼저 분리한다. publisher는 미디어를 올리는 쪽이다.
subscriber는 미디어를 받는 쪽이다. SFU는 둘 사이에서 forwarding 결정을 내린다. layer는 같은 미디어를 여러 품질 후보로 나눠 보는 단위다. 이 네 단어가 섞이면 장애도 섞인다. SFU를 “다자 통신에 쓰는 서버”로 뭉뚱그리지 않는다. 선택적 전달이 내부에서 어떤 책임으로 나뉘는지, 그 책임이 제품 경계와 운영 로그에 어떻게 남아야 하는지에 집중한다. PonsLink나 PonsWarp 같은 제품을 떠올리면 이 경계가 더 분명해진다.
방, 권한, 세션 상태는 중앙에서 일관성을 가져야 한다. 반면 파일 바이트나 미디어 payload는 상황에 따라 직접 경로, relay, storage 경로가 나뉠 수 있다. SFU는 이 중 미디어 payload를 선택적으로 중계하는 후보이지, 모든 실시간 문제의 기본 답은 아니다.
마치며
SFU를 외운 정의로만 보면 “서버가 가운데 있는 구조” 정도로 끝난다. 실제 판단은 더 좁다. SFU는 publisher가 보낸 RTP 흐름이나 품질 layer를 subscriber별로 선택해 전달하는 장치이고, MCU처럼 모든 영상을 새 장면으로 합성하는 장치가 아니다. 이 경계가 선명해야 비용과 로그와 사용자 문구도 선명해진다. SFU를 도입한다는 말은 미디어 서버 하나를 띄운다는 뜻으로 끝나지 않는다. 방 정책, 권한, 품질 후보, layer 선택 기준, region 배치, 장애 문구, 로그 연결을 함께 정해야 한다. 특히 실시간 네트워크는 실패가 사용자 환경에 흩어져 있어 개발자의 좋은 네트워크에서는 늦게 보인다. 특히 SFU에서는 재현 조건을 같이 적어야 의미가 있었다. 로그는 이 비용 이동을 보이게 만드는 장치다. “연결 성공” 하나로 끝내면 운영자는 사용자가 느낀 지연을 따라갈 수 없다. publisher 업로드 bitrate, subscriber별 수신 layer, selected candidate, packet loss, region, forwarding 변경 시점, 재시도 횟수가 사건 단위로 묶여야 한다. 그래야 비용 문제인지, 품질 정책 문제인지, 네트워크 경로 문제인지 구분할 수 있다.
- [ publisher가 올릴 품질 후보를 정했다. simulcast/SVC 중 무엇을 쓸지, 화면 공유와 카메라에 다른 기준을 둘지 적었다.
- [ subscriber별 선택 기준을 정했다. 주 화면, 작은 타일, 모바일, 녹화 대상에 다른 layer를 줄 수 있는지 확인했다.
- [ 서버 egress와 region을 따로 계산했다. 평균 방 크기뿐 아니라 큰 방, 장시간 세션, 지역 간 참여자를 따로 봤다.
- [ 미디어 서버 로그와 앱 로그를 연결했다. 사용자 상태, forwarding 변경, packet loss, selected candidate, 재시도 결과를 같은 사건으로 묶었다.
- [ 사용자 문구를 먼저 써 봤다. 화질 하향, 경로 전환, 상대 환경 제한, 재시도 실패를 내부 용어 없이 설명할 수 있는지 확인했다.