Foundry
실시간 채팅 시스템 설계
심화
핵심

연결 계층 분리

연결을 유지하는 일과 메시지를 처리하는 일은 자원 성격이 다르다

동시 접속 20만 이 이 설계의 첫 제약입니다. 연결은 상시 점유입니다. 아무 메시지가 오가지 않아도 메모리와 소켓을 계속 씁니다. 메시지 처리는 순간 부하라 성격이 다릅니다.

자원 성격이 다르면 따로 늘려야 합니다. 그래서 연결을 받는 계층을 떼어냅니다.

연결을 받는 게이트웨이와 메시지를 처리하는 서비스를 분리한 구조 클라이언트 20만 연결이 계속 열려 있다 연결 게이트웨이 연결만 들고 있다 메시지만 채팅 서비스 순서, 저장, 팬아웃 상시 점유. 메모리와 소켓 연결 수로 늘린다 순간 부하. CPU 처리량으로 늘린다 자원 성격이 다르면 따로 늘려야 한다. 한 서버에 두면 둘 중 하나가 낭비된다 게이트웨이는 어느 사용자가 어디 붙어 있는지만 알면 된다

왜 한 서버에 두면 안 되나

한 서버가 연결과 처리를 함께 맡으면 둘 중 하나가 낭비됩니다.

상황결과
접속자는 많고 대화는 조용하다연결 때문에 서버를 늘렸는데 CPU 가 남는다
접속자는 적고 대화가 활발하다CPU 때문에 늘렸는데 연결 수용량이 남는다

배포도 문제가 됩니다. 채팅 로직을 고칠 때마다 서버를 재시작하면 20만 개의 연결이 한꺼번에 끊깁니다. 클라이언트가 동시에 재접속을 시도해 그 자체가 부하가 됩니다.

계층을 나누면 처리 계층만 배포할 수 있고 연결은 유지됩니다.

게이트웨이가 알아야 하는 것

게이트웨이는 채팅 로직을 모릅니다. 어느 사용자가 어느 게이트웨이에 붙어 있는지만 알면 됩니다. 처리 계층이 "이 사용자에게 보내라" 고 하면 해당 게이트웨이로 넘깁니다.

이 접속 위치 정보를 어디에 두느냐가 다음 판단입니다.

방식특징
공유 저장소에 기록어느 처리 노드에서든 조회한다. 조회가 매 전달마다 붙는다
게이트웨이 전체에 뿌린다조회가 없다. 게이트웨이 수가 많으면 낭비가 크다

접속과 종료가 잦으므로 이 정보는 자주 바뀌고 짧게 살아 있습니다. 영구 저장소보다 만료가 있는 캐시가 맞습니다.

연결이 끊기는 것은 정상이다

모바일에서 연결은 수시로 끊깁니다. 그래서 게이트웨이는 끊김을 오류로 다루지 않습니다. 접속 위치를 지우고, 그 사용자에게 갈 메시지는 채널에 남겨 둡니다. 다시 붙으면 못 받은 것부터 가져갑니다.

여기서 접속 상태를 "끊김 즉시 오프라인" 으로 바꾸면 화면이 깜빡입니다. 짧은 유예를 두고 그 안에 다시 붙으면 상태를 유지합니다.

면접에서 이렇게 나옵니다

Q.동시 접속 20만을 어떤 구조로 받나요

연결을 받는 계층을 떼어냅니다. 연결은 상시 점유이고 메시지 처리는 순간 부하라 자원 성격이 다릅니다.

계층무엇이 상한인가늘리는 기준
연결 게이트웨이메모리와 소켓연결 수
채팅 서비스CPU처리량

한 서버에 두면 둘 중 하나가 낭비됩니다. 조용한 시간대에는 연결 때문에 늘린 서버의 CPU 가 남고, 활발할 때는 그 반대입니다.

배포도 이유입니다. 함께 두면 로직을 고칠 때마다 20만 개의 연결이 끊기고, 동시 재접속이 그 자체로 부하가 됩니다.

흔한 실수: 초당 메시지 수만 계산해 서버 수를 정하는 것. 채팅은 연결이 오래 살아 있는 종류라 요청 수로 환산하면 병목을 반대로 짚습니다.

Q.어느 사용자가 어디 접속해 있는지를 어떻게 관리하나요

게이트웨이는 채팅 로직을 모르고 접속 위치만 압니다. 처리 계층이 전달을 요청하면 해당 게이트웨이로 넘깁니다.

방식특징
공유 저장소에 기록어디서든 조회한다. 조회가 매 전달마다 붙는다
게이트웨이 전체에 뿌린다조회가 없다. 게이트웨이가 많으면 낭비가 크다

이 정보는 접속과 종료가 잦아 자주 바뀌고 짧게 삽니다. 그래서 영구 저장소보다 만료가 있는 캐시가 맞습니다. 게이트웨이가 죽으면 그 항목이 알아서 사라져야 합니다.

흔한 실수: 접속 위치를 데이터베이스 테이블에 두는 것. 초당 수천 번의 갱신과 삭제가 일어나고, 게이트웨이가 비정상 종료하면 정리되지 않은 항목이 남아 없는 곳으로 전달을 시도합니다. 만료가 그것을 대신 치웁니다.

Q.연결이 끊기는 것을 어떻게 다루나요

정상 상황으로 다룹니다. 모바일에서 연결은 수시로 끊깁니다.

게이트웨이는 끊김을 오류로 기록하지 않습니다. 접속 위치를 지우고, 그 사용자에게 갈 메시지는 채널에 남겨 둡니다. 다시 붙으면 못 받은 것부터 가져갑니다.

처리이유
접속 위치 삭제없는 곳으로 전달을 시도하지 않는다
메시지는 채널에 남긴다다시 붙었을 때 이어서 받는다
접속 상태는 유예를 둔다즉시 오프라인으로 바꾸면 화면이 깜빡인다

마지막이 놓치기 쉽습니다. 지하철에서 몇 초 끊기는 것마다 상대 화면의 표시가 바뀌면 신뢰가 떨어집니다. 짧은 유예 안에 다시 붙으면 상태를 유지합니다.

흔한 실수: 끊김을 장애로 집계하는 것. 정상 동작이 지표를 오염시키면 진짜 장애가 묻힙니다. 비정상 종료와 정상 종료를 구분해 세야 합니다.

Q.게이트웨이를 늘릴 때 기존 연결은 어떻게 되나요

기존 연결은 그대로 남습니다. 이미 맺어진 연결을 새 노드로 옮길 수는 없습니다.

새로 들어오는 접속만 새 노드로 갑니다. 그래서 노드를 늘려도 부하가 즉시 고르게 퍼지지 않고, 기존 노드는 연결이 끊길 때까지 계속 붐빕니다.

상황결과
노드를 늘린다새 접속만 분산된다. 기존은 그대로
노드를 줄인다그 노드의 연결이 전부 끊기고 재접속이 몰린다

줄일 때가 더 위험합니다. 한 노드를 내리면 거기 붙어 있던 수만 개가 동시에 재접속을 시도합니다. 그래서 한 번에 하나씩, 간격을 두고 내리고 클라이언트 재시도에 무작위를 섞게 합니다.

흔한 실수: 연결 수를 기준으로 자동 확장을 걸어 두는 것. 늘어난 노드가 즉시 부하를 가져가지 않으므로 지표가 안 내려가고, 그래서 계속 늘어납니다. 확장 기준은 새 접속 수용 여력이어야 합니다.

먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.

읽었으면 문제로 확인해보세요

실시간 채팅 시스템 설계 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.