12. 채팅 시스템 설계
1. 문제 이해 및 설계 범위 확정
어떤앱?
1:1 채팅앱 + 그룹 채팅앱
모바일, 웹 앱
트래픽 규모
5천만 DAU
그룹 채팅 인원 제한 : 100명
주요 기능
1:1 채팅, 그룹 채팅, 사용자 접속 상태 표시 지원, 텍스트 메세지만 주고 받을 수 있음.
메세지 길이 제한 100,000자
종단간 암호화 필요 없음
채팅 이력, 영원히 보관
페이스북 메시지와 비슷한 기능
2. 개략적 설계안 제시 및 동의 구하기
클라이언트로부터 메세지 수신
메세지 수신사 결정 및 전달
수신자가 접속 상태가 아닌 경우, 접속할 때까지 해당 메세지를 보관
폴링 ![[Pasted image 20251207144035.png]]
클라이언트가 주기적으로 서버에세 새 메세지가 있는지 물어보는 방법
계속 물어보는 만큼 서버 자원 불필요한게 낭비되는 단점 있음.
롱폴링 ![[Pasted image 20251207144135.png]]
클라이언트는 새 메세지가 반환되거나 타임아웃 될 때 까지 연결을 유지.
메세지를 보내는 클라이언트, 수신하는 클라이언트가 같은 채팅 서버에 있지 않을 수 있음.
서버 입장에서 클라이언트가 연결을 해제했는지 알 방법 없음
비효율적
웹소켓 ![[Pasted image 20251207144314.png]]
서버가 클라언트에게 비동기 메세지를 보낼 수 있는 방법
개략적인 설계안 ![[Pasted image 20251207144426.png]]
위 기능을 하나의 서버에 구현할 수도 있음.
그러나 규모 확장성은 없을듯
![[Pasted image 20251207144537.png]]
채팅 서버 : 클라이언트 사이에 메세지 중계
접속 상태 서버는 사용자의 접속 여부 관리
API 서버는 로그인, 회원가입, 프로파일 변경 그 외 나머지를 모두 처리
알림 서버 : 푸시 알림
키 값 저장소 에서는 채팅 이력을 보관
저장소
관계형 데이터베이스 or NoSQL?
사용자 프로필, 설정, 친구목록 -> 관계형 데이터베이스
왜?
안정성 보장.
채팅 이력 -> NoSQL
왜?
데이터양이 많고, 그런데 가장 최근에 주고 받은 메세지만 많이 봄
수평적 규모확장에 유리하면서 데이터 접근 지연시간이 낮다
페이스북 메신저 -> HBase
디스코드 -> Cassandra
데이터모델 1:1 채팅을 위한 데이터모델 ![[Pasted image 20251207144934.png]]
그룹 채팅을 위한 메세지 테이블 ![[Pasted image 20251207144949.png]]
channel_id 는 파티션 키로도 사용
메세지 ID
고유해야하며,
ID 값은 정렬 가능해야함 (시간 순서와 일치해야함)
즉 새로운 ID는 이전 ID보다 큰 값이어야함.
스노플레이크
지역적 순서 번호 생성기
3. 상세 설계
![[Pasted image 20251207145933.png]]
서비스 탐색 : 클라이언트에게 가장 적합한 채팅 서버를 추천
사용자 A가 로그인 시도
로드밸런서가 로그인 요청을 API 서버 중 하나로 보냄
API 서버가 인증 처리하고 나면 서비스 탐색 기능 동작해서 해당 사용자를 서비스할 최적의 채팅 서버를 찾음 (주키퍼)
사용자 A는 채팅서버 2와 웹소켓 연결을 맺음
![[Pasted image 20251207150009.png]]
사용자 A가 채팅 서버1 로 메시지 전송
채팅 서버 1 은 ID 생성기를 사용해 해당 메시지의 ID 결정
채팅 서버 1 은 해당 메시지를 메시지 동기화 큐로 전송
메시지가 키-값 저장소에 보관됨
(a) 사용자 B가 접속 중인 경우 메시지는 사용자 B가 접속 중인 채팅 서버(본 예제의 경우에는 채팅 서버2)로 전송됨 (b) 사용자 B가 접속 중이 아니라면 푸시 알림 메시지를 푸시 알림 서버로 보냄
채팅 서버 2 는 메시지를 사용자 B에게 전송. 사용자 B와 채팅 서버2 에는 웹소켓 연결이 있는 상태 이므로 그것을 이용
여러 단말 사이의 메세지 동기화 ![[Pasted image 20251207150349.png]]
cur_max_message_id 라는 변수를 유지.
해당 단말에서 관측된 가장 최근 메세지지의 ID를 추적하는 용도
소규모 그룹 채팅에서의 메시지 흐름 ![[Pasted image 20251207150515.png]]
사용자 A가 그룹 채팅 방에 메세지를 보냈을 때?
A 가 보낸 메세지가 사용자 B, C의 메세지 동기화 큐에 복사됨
이 구조는 소규모 그룹 채팅에 적합
위챗에서 사용하는 경우
![[Pasted image 20251207150630.png]]
사용자는 하나의 큐를 가지고 있어서, 여러 사용자로부터 오는 메세지를 수신하는 방법
접속상태 표시
사용자 로그인
웹소켓 연결이 맺어지고 나면, last_active_at 타임 스탬프값을 보관.
이 절차가 끝나면 사용자는 접속 중 상태로 표시됨.
로그아웃
online -> offline 으로 변경
접속 장애
heartbeat 검사.
온라인 상태의 클라이언트로 하여금 주기적으로 박동 이벤트를 접속 상태에 보내고, 마지막 이 이벤트를 받은지 x 초 이내에 또 다른 박동 이벤트를 받으면 해당 사용자의 접속 상태를 계속 온라인으로 유지.
그렇지 않으면 오프라인으로 바꿈
상태 정보의 전송 ![[Pasted image 20251207151029.png]]
그룹 크기가 클면, 비용이 많이 든다.
그래서 그룹 크기를 제한하는 이유
마무리
종단 간 암호화
캐시
로딩 속도 개선
오류 처리
사진, 비디오등의 미디어를 지원하는 방법
Last updated