모음/[가상면접 사례로 배우는 대규모 시스템 설계 기초]

[가상면접 사례로 배우는 대규모 시스템 설계 기초] ch12. 채팅 시스템 설계

ttoance 2024. 6. 15. 21:42

 

요구사항

1. 응답지연이 낮은 일대일 채팅 기능

2. 최대 100명까지 참여할 수 있는 그룹 채팅 기능

3. 사용자의 접속상태 표시 기능

4. 다양한 단말 지원, 하나의 계정으로 여러 단말에 동시 접속 지원

5. 푸시 알림 

+) 5천만 DAU 처리할 수 있도록 설계 

 

1차 설계 

1. 설계 전 고려사항 : 네트워크 통신 프로토콜 결정 

- 메시지 요청 시나리오에서는 HTTP 프로토콜 : keep-alive 헤더 사용해서 클라이언트와 서버 사이의 연결을 유지 

ㄴ 페이스북 같은 많은 대중적 채팅 프로그램이 초기에 HTTP를 사용함 

- 메시지 수신 시나리오에서는 HTTP 프로토콜을 사용하기에는 서버에서 클라이언트로 임의 시점에 메시지를 보낼 때 사용 못하므로, 이때를 위해 다른 기법을 사용한

ㄴ 폴링(polling), 롱 폴링(long polling), 웹 소켓(websocket)

 

     
폴링
- 클라이언트가 주기적으로 서버에게 새 메시지가 있느냐고 물어보는 방법
- 단점
ㄴ 폴링을 자주하면 비용이 올라간다.
ㄴ 답해줄 메시지가 없는 경우에는 서버 자원이 불필요하게 낭비된다.
롱폴링
- 클라이언트는 새 메시지가 반환되거나 타임아웃될 때까지 연결을 유지하는 방법
- 새 메시지를 받으면 기존 연결을 종료하고 서버에 새로운 요청을 보내어 모든 절차를 다시시작함 
- 약점
ㄴ 메시지를 보내는 클라이언트와 수신하는 크라이언트가 같은 채팅 서버에 접속하게 되지 않을 수 있음 
ㄴ 서버 입장에서는 클라이언트가 연결을 해제했는지 아닌지 알 좋은 방법이 없다. 
웹소켓
- 서버가 클라이언트에게 비동기 메시지를 보낼 때 가장 널리 사용되는 기술 
- 동작원리
ㄴ 클라이언트가 연결을 시작해서 처음에는 http이지만 특정 핸드셰이크 절차 거치면서 웹소켓 연결로 업그레이드됨

*웹소켓을 이용하면 메시지를 보낼 때나 받을때나 동일한 프로토콜을 사용할 수 있음 

 

2. 1차 설계 

1) 무상태 서비스 : 로그인, 회원가입, 사용자 프로파일 표시 등을 처리하는 서비스 

2) 상태 유지 서비스 : 채팅 서비스 

3) 제 3자 서비스 연동 : 푸시 알림 

 

2차 설계 

1. 설계 전 고려사항 : 규모 확장성 

- 동시 접속자가 1M이라고 가정하면, 접속당 서버 10K의 서버 메모리가 필요한다고 보면

10GB 메모리만 있으면 모든 연결을 처리할 수 있음 

- 하지만 서버 한대에 담은 설계안으로는 SPOF의 문제가 발생할 수 있음 

 

2. 설계 전 고려사항 : 저장소

- 채팅 시스템에서 다루는 데이터는 보통 두 가지이다. 

ㄴ 사용자 프로파일, 설정, 친구 목록처럼 일반적인 데이터로 -> 관계형 데이터베이스에 보관 

ㄴ 채팅 시스템의 고유한 데이터 -> 키-값 저장소 

*키-값 저장소의 장점 

- 수평적 규모확장이 쉬움

- 데이터 접근 지연시간이 낮음 

- 이미 많은 시스템이 키 값 저장소를 채택하고 있음. 페이스북 메신저는 Hbase를, 디스코드는 Cassandra를 이용 

 

 

3. 2차 설계 

- 채팅 서버는 클라이언트 사이에 메시지를 중계하는 역할을 담당한다.

- 접속상태 서버는 사용자의 접속 여부를 관리한다.

- API 서버는 로그인, 회원가입, 프로파일 변경 등 그 외 나머지 전부를 처리한다.

- 알림 서버는 푸시 알림을 보낸다.

- 키-값 저장소에는 채팅 이력을 보관하나. 시스템에 접속한 사용자는 이전 채팅 이력을 전부 보게 될 것이다. 

 

 

상세 설계 

1. 서비스 탐색 

- 주된 역할은 클라이언트에게 가장 적합한 채팅 서버를 추천하는 것. 

- 널리 쓰이는 오픈 소스 솔루션으로 아파치 주키퍼등이 있음 

2. 메시지 흐름 

1) 1:1 채팅 메시지 처리 흐름 

- 사용자 A가 채팅 서버 1로 메시지 전송

- 채팅 서버1은 ID 생성기 사용해 해당 메시지의 ID 결정

- 채팅 서버1은 해당 메시지를 메시지 동기화 큐로 전송 

- 메시지가 키-값 저장소에 보관됨

- 사용자B가 접속 중이면 사용자B가 접속 중인 채팅 서버로 전송, 아니라면 푸시 알림 메시지를 푸시 알림 서버로 보냄

- 채팅 서버2는 메시지를 사용자B에게 전송

2) 여러 단말 사이의 메시지 동기화 

- cur_max_message_id : 해당 단말에서 가장 최신의 메시지 id 

 

3) 소규모 그룹 채팅에서의 메시지 흐름 

- 새로운 메시지가 왔는지 확인하려면 자기 큐만 보면 되니까 메시지 동기화 플로가 단순하다.

- 그룹이 크지 않으면 메시지를 수신자별로 복사해서 큐에 넣는 작업의 비용이 문제가 되지 않는다. 

3. 접속상태 표시 

1) 사용자 로그인 : 웹소켓 연결이 맺어지고 나면 last_active_at을 가지고 키-값 저장소에 보관 

2) 로그아웃 : 키-값 저장소에 보관된 사용자 상태가 offline으로 변경

 

4. 접속 장애 

- 간단한 방법은 사용자를 오프라인 상태로 표시하고 연결이 복구되면 온라인 상태로 변경하는 것. 

ㄴ 짧은 시간동안 인터넷이 끊어졌다 복구되는 일이 흔하기 때문에, 이럴때마다 접속 상태 변경하는 것은 지나침

- 박동 heartbeat 검사를 통해 x초 이내에 또 다시 이벤트 받으면 접속상태를 유지 

5. 상태 정보의 전송 

- 발행-구독 모델을 사용

ㄴ 가령 사용자 A의 접속상태가 변경되었다고 하면, 그 사실을 A-B, A-C, A-D에 쓰는것. 

ㄴ 그룹 크기가 작을 때 효과적이다. 

ㄴ 그룹 크기가 크다면, 해소하는 한 가지 방법은 그룹 채팅에 입장하는 순간에만 상태 정보 읽거나 수동으로 상태 정보 갱신하도록 유도하는것. 

 

마무리 

1. 채팅 앱을 확장하여 사진이나 비디오 등의 미디어 지원 : 미디어 파일은 텍스트에 비해 크기가 크므로, 압축방식, 클라우드 저장소, 썸네일 생성 등을 이야기해볼 수 있음 

2. 종단 간 암호화 : 왓츠앱은 메시지 전송에 있어 종단 간 암호화를 지원 

https://faq.whatsapp.com/820124435853543/?locale=en_US

 

About end-to-end encryption | WhatsApp Help Center

 

faq.whatsapp.com

3. 캐시 : 클라이언트에 이미 읽은 메시지 캐시해두면 서버와 주고받는 데이터 양 줄일 수 있음

4. 로딩 속도 개선 : 슬랙은 사용자의 데이터, 채널 등을 지역적으로 분산하는 네트워크 구축해 앱 로딩 속도 개선함 

5. 오류 처리 

- 채팅 서버 오류 : 채팅 서버 하나에 수십만 사용자가 접속해있는데, 하나가 죽으면 서비스 탐색 기능이 동작하여 클라이언트에게 새로운 서버를 배정하고 다시 접속할 수 있도록 해야함

- 메시지 재전송 : 재시도나 큐 

 

 

 

 

 

 

반응형