webRTC는 브러우저 간 실시간 오디오 및 비디오 통신을 가능하게 하는 기술이다. 해당 기술은 연결 방식에 따라 구조가 3가지로 나뉘며, 성능과 확장성에도 큰 영향을 미친다.
1. P2P (Peer to Peer)
브러우저 간 직접 연결로 중계 서버 없이 모든 사용자가 서로의 스트림을 주고 받는 방식이다.
장점: 구현이 단순하며 서버 부하가 없다.
단점: 참여자 수가 늘어날 수록 연결 수가 기하급수적으로 증가하게 된다.
내가 처음 구현했던 방식이다. 1:1 통신에는 문제가 없었고, 이 구조로 기능을 완성하고자 했지만, 3명 이상의 통신에서는 확장성의 한계를 마주하게 됐다 😂...
2. SFU (Selective Forwarding Unit)
클라이언트가 송신한 미디어 스트림을 서버가 받아서 다른 클라이언트에게 전달 해주는 구조이다.
장점: 서버 자원 소모가 적고 클라이언트의 업로드/다운로드의 부담을 줄일 수 있다.
단점: 서버가 필요하며 상대적으로 P2P보다는 구현 복잡도가 있다.
기존에 사용하던 P2P의 경우 1:1 통신에 적합한 방식을 다자간 통신으로 만들다보니 코드가 매우 매우 복잡해 지고, 카메라 렌더링이 가끔 먹통이 되는 성능 이슈가 있었다.
현재의 리팩토링 과정에서는 SFU 기반 구조로 전환하고 있다!
3. MCU (Multipoint Control Unit)
서버가 모든 클라이언트의 미디어를 받아서 하나의 스트림으로 혼합 후 다시 클라이언트에게 전송하는 방식이다.
장점: 각 클라이언트는 단일 스트림만 수신하면 되기 때문에 성능 부담이 적다.
단점: 서버 성능 부담이 매우 크며 비용과 복잡도가 증가한다.
해당 구조의 경우에는 사이드 프로젝트에서 구현하는 것이 마땅하지 않다고 판단했다.
나의 선택은 ?
초기에는 Python으로 구현된 DeepFace 표정 분석 기능을 위해 백엔드를 Django로 채택했다. 이 시점에서는 표정 분석과 상대와 통신이 가능한가? 의 기술 구현을 목표로 잡았기 때문에 P2P 구조로 구현했으면 큰 문제가 발생하지 않았다.
발표를 두 달 앞둔 시점에서 서비스의 주제가 화상 회의이기 때문에 1:1통신이 아닌 다자간의 통신까지 구현되는 것이 적합하다는 피드백을 받았고, 이 과정에서 구조적 한계에 직면하게 됐다.
Django의 경우 WebRTC 다자간 구현은 레퍼런스가 없다고 해도 무방한 상태였으며,
기존 백엔드 담당자가 교환학생으로 빠지게 되면서,
Node.js를 사용했던 경험이 조금이라도 있었던 내가 전담하게 되었다.
Kurento(SFU 기반 미디어 서버)를 도입하려 했으나, 이미 시간이 촉박한 시점에서 해당 부분을 공부하며 혼자 구현하는 것은 무리라고 생각하여 P2P 방식으로 다시 다자간 구조를 직접 구현하게 되었다.
Node는 Django에 비해 레퍼런스가 비교적 많았기 때문에 소스 코드들을 참고하며 다자간 통신 구현을 성공했지만!
코드가 뒤엉켜 있고, 카메라 렌더링이 중간에 끊기거나 한 참가자가 나갔을 경우 전체 참가자 간 연결이 불안정해지는 문제가 발생했다.
현재는 구조부터 다시 공부하게 되면서 P2P와 SFU, MCU 차이를 이해하게 되었고,
여러 장점과 단점을 조합해 고민한 결과 SFU를 채택하여 리팩토링을 진행 중이다!
기술적인 도전도 물론 중요하지만, 이 경험을 통해 단순히 어떻게 구현해야 하는가를 넘어서서 왜 이 방식을 선택해야 하는 지에 대한 구조적인 고민도 하게 됐다
부족한 여건 속에서도 주어진 자원과 시간 안에서 최선의 결정을 내렸던 경험을 통해 앞으로 어떤 기술이든 더 넓게 보고, 깊게 고민할 수 있는 시야를 갖게 되었다...! 비록 매우 힘들었지만 🤣..!