채팅 설계도 요구사항을 기능과 비기능으로 나누고 범위 밖을 먼저 자르는 것에서 시작합니다. 이 토픽은 아래 하나의 요구사항을 끝까지 풉니다.
| 항목 | 값 |
|---|
| 서비스 | 팀 메신저 |
| 동시 접속 | 20만 |
| 채널 크기 | 평균 12명, 최대 5만 명 |
| 메시지 | 하루 2억 건 |
| 전달 지연 | 300ms 안에 상대 화면까지 |
| 순서 | 채널 안에서만 보장한다. 전역 순서는 포기 |
기능 요구사항과 범위 밖
| 구분 | 내용 |
|---|
| 이번에 만든다 | 채널에 메시지 보내기, 실시간 수신, 지난 메시지 조회, 읽음 표시, 접속하지 않은 사람에게 알림, 접속 상태와 입력 중 표시 |
| 범위 밖 | 음성과 영상 통화, 파일 미리보기, 메시지 검색, 종단간 암호화 |
범위 밖을 말하는 것이 실력입니다. 검색을 빼면 저장 구조가 단순해지고, 종단간 암호화를
빼면 서버가 내용을 볼 수 있어 알림 문구를 만들 수 있습니다. 뺀 것이 남은 설계를 바꿉니다.
비기능 요구사항이 설계를 정한다
| 숫자 | 강제하는 것 | 왜 |
|---|
| 동시 접속 20만 | 연결 계층 분리 | 연결을 유지하는 일과 메시지를 처리하는 일은 자원 성격이 다르다 |
| 채널 최대 5만 명 | 팬아웃 설계 | 한 번 보낸 메시지가 5만 개의 전달로 늘어난다 |
| 지연 300ms | 서버가 밀어주기 | 폴링은 간격만큼 지연이 쌓인다 |
| 채널 내 순서만 | 채널 단위 파티션 | 전역 순서를 포기하면 채널별로 나눠 처리할 수 있다 |
순서를 어디까지 보장할지가 확장을 정한다
전역 순서를 보장하려면 모든 메시지가 한 곳을 지나야 합니다. 그러면 그곳이 상한이 됩니다.
채널 안에서만 보장하기로 정하면 채널을 기준으로 나눠 처리할 수 있습니다. 다른 채널의
메시지가 서로 뒤바뀌어도 사용자는 알 수 없습니다. 한 대화방 안에서만 순서가 맞으면 됩니다.
이것이 요구사항을 읽는 방법입니다. 무엇을 포기해도 되는지 찾으면 확장 경로가 열립니다.
평균값은 반대로 읽는다
평균 12명 이라는 숫자는 과설계를 막는 쪽으로 씁니다. 최대가 5만 명 이라
팬아웃 설계가 필요하지만, 실제 채널 대부분은 12명이라 보낼 때 바로 전달해도 됩니다.
그래서 설계는 하나가 아니라 두 갈래가 됩니다. 작은 채널은 즉시 전달, 큰 채널만 다른 경로로
보냅니다. 최대값만 보고 모든 채널을 무겁게 처리하면 흔한 경우가 느려집니다.
Q.채팅 서비스의 요구사항을 어떻게 정리하시겠습니까
기능과 비기능으로 나누고 범위 밖을 먼저 자릅니다.
| 구분 | 내용 |
|---|
| 기능 | 메시지 보내기, 실시간 수신, 지난 메시지 조회, 읽음 표시, 알림, 접속 상태 |
| 범위 밖 | 통화, 파일 미리보기, 검색, 종단간 암호화 |
| 비기능 | 동시 접속 20만, 채널 최대 5만 명, 지연 300ms, 채널 내 순서만 |
그다음 각 숫자가 어떤 설계를 강제하는지 말합니다. 동시 접속 20만 은 연결 계층을
분리하게 만들고, 채널 최대 5만 명 은 팬아웃 설계를 요구합니다.
흔한 실수: 비기능을 "실시간, 고가용성, 확장성" 처럼 형용사로 나열하는 것. 숫자와 그
숫자가 강제하는 결론이 없으면 아무 설계도 정해지지 않습니다. 그리고 범위 밖을 말하지
않으면 통화와 검색까지 얘기가 번져 무엇도 깊게 다루지 못합니다.
Q.메시지 순서를 어디까지 보장해야 하나요
채널 안에서만 보장합니다. 전역 순서는 포기합니다.
전역 순서를 보장하려면 모든 메시지가 한 곳을 지나야 하고, 그러면 그곳이 처리량 상한이
됩니다. 채널 단위로만 보장하면 채널을 기준으로 나눠 처리할 수 있습니다.
채널 A 의 메시지끼리는 순서가 맞아야 한다
채널 A 와 채널 B 의 메시지가 서로 뒤바뀌어도 사용자는 알 수 없다
사용자는 한 대화방을 보고 있으므로 그 안에서만 맞으면 됩니다. 필요 없는 보장을 찾아
버리는 것이 확장 경로를 여는 방법입니다.
흔한 실수: 순서를 타임스탬프로 맞추겠다고 답하는 것. 서버 시계가 조금씩 다르고 같은
밀리초에 두 메시지가 들어올 수 있습니다. 순서가 중요하면 채널마다 증가하는 번호를
서버가 붙이는 편이 확실합니다.
Q.이 요구사항에서 가장 먼저 한계에 닿는 곳은 어디인가요
연결 유지입니다. 메시지 처리량보다 먼저 걸립니다.
하루 2억 건 을 초로 나누면 약 2,300건
피크를 5배로 잡아도 초당 1만건 남짓
반면 동시 접속은 20만 이 계속 열려 있다
초당 1만 건 쓰기는 파티션을 나누면 처리됩니다. 그런데 20만 개의 연결은 아무 메시지가
오가지 않아도 메모리와 파일 디스크립터를 계속 점유합니다.
| 항목 | 성격 |
|---|
| 메시지 처리량 | 순간 부하. 나눠서 처리한다 |
| 연결 수 | 상시 점유. 서버당 수용량이 상한이 된다 |
그래서 연결을 받는 계층과 메시지를 처리하는 계층을 나눕니다. 자원 성격이 다르면 따로
늘려야 합니다.
흔한 실수: 초당 메시지 수만 계산하고 끝내는 것. 채팅은 연결이 오래 살아 있는 종류라
요청 수로 환산한 숫자만 보면 병목을 반대로 짚습니다.
Q.채널 최대 인원이 5만 명이면 모든 채널을 같은 방식으로 처리해야 하나요
아닙니다. 평균이 12명 이므로 대부분의 채널에는 과설계입니다.
큰 채널용 팬아웃 설계는 공짜가 아닙니다. 전달을 큐로 넘기고, 진행 상태를 추적하고, 실패한
전달을 다시 시도하는 구조가 붙습니다.
| 채널 크기 | 맞는 경로 |
|---|
| 평균 12명 수준 | 보낼 때 바로 전달한다 |
| 수천 명 이상 | 큐로 넘겨 나눠 전달한다 |
그래서 설계는 두 갈래가 됩니다. 인원 수를 보고 경로를 고릅니다.
흔한 실수: 최대값만 보고 하나의 경로로 통일하는 것. 요구사항에 평균이 함께 적혀 있는
이유가 이것입니다. 최대는 무엇이 가능해야 하는지를 정하고, 평균은 무엇이 흔한지를
정합니다. 흔한 경우를 무겁게 만들면 전체가 느려집니다.
먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.
읽었으면 문제로 확인해보세요
실시간 채팅 시스템 설계 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.