[PonsLink] 실시간 메시지는 모두 같은 줄에 서면 안 된다
실시간 메시지를 한 줄에 세우면 안 됐다. 채팅과 제어 메시지와 파일 조각은 모두 메시지이지만, 늦어졌을 때 사용자가 느끼는 피해가 같지 않다.
처음에는 단일 큐로 충분하다고 생각했다. 도착한 순서대로 처리하면 구현이 단순하고, 순서를 설명하기도 쉬워 보였다. 혼잡 구간에서 이 가정이 깨졌다. 파일 전송이 밀리면 제어 메시지까지 늦어지고, 사용자는 방 전체가 멈춘 것으로 느꼈다.

메시지마다 늦어도 되는 시간이 달랐다
채팅은 조금 늦어도 이어질 수 있지만, 연결 종료나 권한 변경은 늦게 처리하면 잘못된 상태가 남는다. 파일 조각은 순서를 지켜야 하지만 제어 메시지보다 먼저 처리할 이유는 없다.
모든 것을 하나의 FIFO에 넣으면 공정해 보인다. 실제로는 가장 중요한 메시지가 가장 큰 데이터 뒤에서 기다리게 된다. 큐의 공정성을 지키려다 제품의 반응성을 잃은 셈이다.

큐를 채널별로 나누다
메시지 성격에 따라 큐를 나누고 우선순위를 달리했다. 제어와 상태 변경을 먼저 처리하고, 파일 조각은 백프레셔를 따르며, 채팅은 사용자 경험을 해치지 않는 범위에서 흘려보낸다.
이것은 순서를 포기한 것이 아니다. 같은 채널 안에서는 순서를 유지하되, 서로 다른 책임의 메시지가 하나의 병목을 공유하지 않게 만든 것이다.
혼잡할 때 먼저 버틸 것
큐가 차면 모두를 계속 쌓는 대신, 어떤 메시지가 재생성 가능하고 어떤 메시지가 반드시 보존돼야 하는지 구분해야 한다. 파일 조각은 확인 상태가 있어야 다시 요청할 수 있고, 오래된 중간 화면 상태는 최신 상태로 대체할 수 있다.
큐 설계는 자료구조 선택보다 실패 시 사용자에게 무엇을 보여 줄지 정하는 일에 가까웠다. 제어가 살아 있고 현재 상태를 설명할 수 있으면 일부 지연은 견딜 수 있다.
마치며
실시간 메시지를 하나의 줄로 처리하는 단순함은 혼잡할 때 가장 먼저 깨졌다. 다음 큐를 설계할 때는 메시지 이름이 아니라 지연 허용 범위와 재생성 가능 여부부터 나눈다.