[TURN 딥다이브] P2P인데 왜 TURN 비용이 발생하는가
P2P 제품을 만들면서 TURN 비용을 계산한다는 말은 처음엔 이상하게 들린다. 사용자는 피어끼리 직접 보내는 기능을 기대하고, 개발자도 서버 대역폭을 줄이려고 WebRTC를 본다. 그런데 직접 경로가 막히면 TURN 서버가 실제 payload를 대신 받아서 다시 보내야 한다. 그 순간 P2P라는 말만으로는 비용을 설명할 수 없다. TURN은 무료 안전망이 아니라 사용량이 찍히는 릴레이 경로다. 로그를 다시 펼쳤을 때 눈에 들어온 건 예쁜 성공 화면이 아니라, TURN 주변에서 반복되던 작은 끊김이었다. 그래서 용어 사전 대신, 그 날 무엇을 보고 무엇을 바꿨는지부터 적는다. 아래에서는 TURN을 중심으로, 깨진 가정과 다시 그은 경계를 순서대로 남긴다.

TURN 비용을 마주한 이유
사용자 경험에서는 relay 전환을 오류처럼 보이지 않게 하는 것이 중요하다. 직접 연결이 실패해 우회 경로로 바뀌는 것은 정상 fallback일 수 있다. 다만 속도나 제한이 달라질 수 있으므로 조용히 숨기기만 해도 안 된다. "직접 연결이 어려워 우회 경로로 전송합니다"처럼 짧게 알려 주면 사용자는 상황을 이해하고, 느려졌을 때도 제품이 멈췄다고 오해할 가능성이 줄어든다.
결국 TURN 비용은 "돈이 드니 쓰지 말자"가 아니다. 직접 연결이 실패하는 현실을 받아들이되, 어떤 사용량까지 relay로 책임질지 정하자는 말이다. 지표와 정책이 있으면 TURN은 제품의 신뢰도를 높이는 fallback이 된다. 지표 없이 켜 두면 나중에 비용표와 장애 문의로 돌아온다. 특히 TURN에서는 재현 조건을 같이 적어야 의미가 있었다. TURN을 비용 항목으로만 보면 무조건 줄이고 싶어진다.
하지만 어떤 사용자에게는 relay가 유일한 성공 경로다. 그래서 줄여야 할 것은 TURN 자체가 아니라 불필요하게 오래 붙잡는 직접 시도, 설명 없는 대기, 큰 파일을 무작정 밀어 넣는 전송 정책이다. 비용 절감도 결국 사용자에게 끝까지 전달되는 경로를 남겨 둔 뒤에 해야 한다. TURN credential은 짧게 관리하는 편이 안전하다. 장기 credential이 클라이언트에 노출되면 악용 여지가 커진다.
동시에 너무 짧으면 정상 연결 중 갱신 문제가 생긴다. 따라서 발급, TTL, 갱신 실패 문구, 서버 로그를 같이 설계해야 한다. 사용자는 인증 만료라는 내부 원인을 몰라도 되지만, 제품은 재시도할지 새 방을 만들지 안내해야 한다.

겉으로 비슷한 말들
TURN 서버를 직접 운영할지 관리형 서비스를 쓸지도 제품 단계에 따라 다르다. 직접 운영하면 통제권이 커지지만 region, 모니터링, abuse 대응을 스스로 책임져야 한다. 관리형은 시작이 빠르지만 가격표와 제한을 잘 읽어야 한다. 어느 쪽이든 애플리케이션 로그와 비용 로그를 연결하지 못하면 나중에 어떤 기능이 비용을 만들었는지 알기 어렵다.
가격 정책과도 바로 연결된다. 무료 플랜에서 무제한 TURN relay를 열면 악용과 비용을 막기 어렵다. 유료 플랜에서도 대용량 파일을 모두 relay로 처리하겠다고 약속하면 마진이 쉽게 흔들린다. 그래서 파일 크기별 정책, 일일 전송량, 동시 전송 수, fallback 선택 기준을 제품 기획 단계에서 정해야 한다. 기술 설정처럼 보이지만 실제로는 가격표와 약관에 닿는 문제다.
1GB 파일을 TURN relay로 보낸다고 생각해 보자. 송신자가 TURN 서버로 1GB를 올리고, TURN 서버가 수신자에게 1GB를 내려준다. 운영비 관점에서는 최소 2GB급 대역폭 이벤트로 봐야 한다. 여기에 지역 간 트래픽, 동시 연결, 재시도, 실패 후 재전송까지 붙으면 계산은 더 커진다. 그래서 "직접 연결이 안 될 때만 쓰니까 괜찮다"는 말은 relay 비율과 파일 크기를 같이 보지 않으면 위험하다.
대용량 파일에서는 사용자에게 선택권을 주는 방식도 고려할 만하다. 직접 연결이 실패했을 때 작은 파일은 relay로 계속 보내고, 큰 파일은 Cloud Drop을 권하는 식이다. 이때 문구는 정직해야 한다. "현재 네트워크에서는 직접 전송이 어려워 저장 후 전달 방식이 더 안정적입니다"처럼 말하면 사용자는 왜 경로가 바뀌는지 이해한다. 내부 비용 정책을 사용자에게 떠넘기는 문장이 되어서는 안 된다.
팀에서 TURN을 논의할 때는 아키텍처 그림 옆에 비용 단위를 같이 쓴다. 몇 명이 얼마나 오래 relay를 타는지, 파일 크기는 얼마인지, egress가 어느 region에서 나가는지 적어야 한다. 그래야 TURN을 켤지 말지가 감정적인 논쟁이 아니라 서비스 약속의 일부가 된다. 특히 TURN에서는 재현 조건을 같이 적어야 의미가 있었다.

오해가 만든 잘못된 구현
운영자는 TURN 서버를 단순 인프라로만 보면 안 된다. CPU보다 대역폭이 먼저 병목이 될 수 있고, region이 멀면 연결은 성공해도 사용자 체감이 나쁘다. 특정 시간대에 relay가 몰리면 일반 연결 실패율보다 속도 문의가 먼저 늘 수 있다. 모니터링 대시보드에는 연결 성공률뿐 아니라 relay throughput, active allocation, auth failure, region별 지연이 있어야 한다. P2P인데 왜 TURN 그래서 이 주제의 공부는 늘 구현 체크리스트로 끝내는 편이 좋다.
어떤 값을 기록할지, 어떤 제한을 문서화할지, 어떤 fallback을 정상 흐름으로 볼지 정한다. 이 정도까지 내려오면 기술 약어가 제품의 약속으로 바뀐다. 반대로 여기까지 내려오지 않으면 글은 그럴듯하지만 다음 장애 때 다시 검색창을 열게 된다. TURN 비용을 줄이는 가장 나쁜 방법은 실패를 사용자에게 떠넘기는 것이다. relay를 끄고 "직접 연결만 지원"이라고 말할 수도 있지만, 그러면 제한된 네트워크 사용자는 제품을 쓸 수 없다.
반대로 모든 사용량을 조용히 relay로 흘리면 운영비가 제품을 밀어낸다. 좋은 설계는 그 사이에서 사용자의 데이터 크기와 네트워크 상태에 맞는 경로를 고르고, 그 선택을 이해할 수 있게 말한다. TURN을 설계할 때는 "언제 끊을 것인가"도 정해야 한다. relay 연결을 무한정 유지하면 비용과 자원 점유가 커진다. 비활성 세션을 언제 정리할지, 파일 전송이 멈춘 상태를 얼마나 기다릴지, 사용자가 탭을 닫았을 때 allocation을 어떻게 회수할지 기준이 필요하다.
이 기준은 너무 공격적이면 정상 사용자를 끊고, 너무 느슨하면 비용을 만든다. TURN 경로에서는 사용자에게 비용을 말할 필요는 없지만 기다림의 이유는 말해야 한다. 직접 연결이 어려워 중계 경로를 쓰는 중인지, 파일이 커서 시간이 걸리는지, 네트워크 변경을 권해야 하는지 구분해야 한다. 운영 로그에는 그 문장 뒤의 바이트와 시간을 남겨야 한다.
특히 TURN에서는 재현 조건을 같이 적어야 의미가 있었다. TURN 비용을 볼 때는 성공률과 가격을 함께 둬야 한다. TURN을 끄면 비용은 줄지만 연결 실패율이 올라간다. TURN을 넉넉하게 열면 성공률은 올라가지만 대역폭 비용, abuse 대응, quota 정책이 필요해진다. 둘 중 하나만 정답은 아니다. 제품이 어떤 데이터를 보내고, 사용자가 어느 정도의 실패를 받아들일 수 있으며, 유료 플랜에서 어떤 약속을 할지에 따라 기준이 달라진다.
TURN를 설명할 때 서버/클라이언트/사용자 중 누구 문장으로 말하는지 먼저 고르면 논쟁이 줄었다.
P2P와 relay의 경계 나누기
내가 먼저 확인하는 항목은 대역폭, credential, region, abuse다. 대역폭은 relay 사용량과 바로 연결된다. credential은 만료와 노출 위험을 만든다. region은 지연과 비용에 영향을 준다. abuse는 TURN을 열린 프록시처럼 쓰지 못하게 막는 문제다. 이 네 가지 없이 TURN을 켜면 연결은 좋아 보일 수 있지만 운영자는 뒤늦게 요금과 장애를 받는다. region도 생각보다 중요하다. 모든 사용자를 하나의 TURN region으로 보내면 단순하지만 지연이 커질 수 있다.
미디어에서는 왕복 시간이 체감 품질에 바로 반영되고, 파일 전송에서도 느린 relay는 사용자가 취소하는 이유가 된다. 여러 region을 둘수록 비용과 운영 복잡도는 늘어난다. 그래서 처음부터 전 세계 최적화를 하자는 뜻이 아니라, 어떤 지역 사용자에게 어떤 제한이 생기는지 관찰할 수 있게 만들어야 한다. 초기 제품에서는 완벽한 비용 모델보다 측정 가능한 최소 모델이 더 중요하다.
relay로 전환된 세션 수, relay 전송량, 파일 크기 분포, 중단률 정도만 꾸준히 봐도 위험 신호를 잡을 수 있다. 나중에 사용자가 늘면 region 분리, quota, plan별 제한, cloud fallback 기준을 더 세밀하게 조정한다. 측정 없이 감으로 정한 TURN 정책은 대개 너무 느슨하거나 너무 빡빡하다. 다시 볼 질문은 단순하다. relay 사용률을 측정하고 있는가. 파일 크기별 TURN 정책을 정했는가. credential TTL과 갱신 실패를 테스트했는가. quota와 rate limit을 abuse 대응과 함께 설계했는가. 이 네 가지를 답할 수 있으면 TURN은 막연한 비용 걱정이 아니라 연결 성공률과 운영비 사이의 조절 장치가 된다.
비용이 발생하는 순서
마지막 판단은 늘 사용자 시간으로 돌아온다. 내부적으로 어떤 후보가 실패했는지보다 사용자가 몇 초를 기다렸고, 그 뒤 무엇을 할 수 있었는지가 제품의 기억으로 남는다. 이 차이를 남겨 두면 다음 구현도 덜 흔들린다. 비용 최적화는 연결 성공률을 해치지 않는 선에서 해야 한다. relay 후보를 너무 늦게 주면 제한된 네트워크 사용자가 오래 기다린다.
반대로 처음부터 relay를 강제하면 직접 연결 가능성을 버린다. ICE 후보 정책과 TURN 제공 방식은 제품의 인내 시간과 맞아야 한다. 사용자가 3초를 기다릴 수 있는 기능과 30초를 기다릴 수 있는 기능은 다른 정책을 가져야 한다. TURN 비용도 좋은 네트워크에서는 잘 보이지 않는다. 직접 경로가 대부분 성공하면 relay 청구서는 작다. 하지만 특정 고객군이 보안망 뒤에 있거나 큰 파일을 자주 보내면 비용 곡선이 달라진다.
그래서 작은 샘플의 평균보다 relay 비율의 상위 구간을 보는 편이 안전하다. 특히 TURN에서는 재현 조건을 같이 적어야 의미가 있었다. TURN은 Traversal Using Relays around NAT의 약자다. 피어 사이에 직접 연결이 어려울 때 중간 서버를 통해 데이터를 전달한다. STUN이 주소를 확인하는 역할에 가깝다면 TURN은 바이트를 운반한다. 그래서 책임이 무겁다. 서버는 한쪽에서 데이터를 받고 다른 쪽으로 보낸다.
파일 전송이라면 파일 크기만큼, 미디어라면 재생 시간과 bitrate만큼 비용이 쌓인다. 제품 문구도 비용 구조를 숨기지 않는 쪽이 낫다. "우회 경로로 연결되었습니다. 네트워크 환경에 따라 속도가 달라질 수 있습니다"처럼 말하면 사용자는 직접 경로와 relay 경로의 차이를 완전히 몰라도 상황을 이해한다. 대용량 파일에서 relay 제한을 둔다면 미리 알려야 한다.
실패한 뒤에야 "전송할 수 없음"을 보여 주면 사용자는 제품이 변덕스럽다고 느낀다. '[TURN 딥다이브 P2P인데 왜 TURN 비용이 발생하는가'을 관통하는 질문은 이 섹션에서도 같았고, 답만 더 구체적이 됐다.
마치며
이 글에서 확인한 경계는 다음 변경의 기준으로 남겼다.