회사 프로젝트에서 기획부터 처음에 참여한 첫 프로젝트는 웹소켓을 이용한 실시간성이 보장되어야 하는 프로젝트 였습니다.
백엔드에서 종종 실시간에 대한 부분은 시스템 구조상 엄청난 부분인데, 간만에 미디엄의 블로그에서 시스템디자인을 전문적으로 여러 건 다룬 글을 발견해서 기록합니다. (글 링크는 하단부 레퍼런스 링크 참고)
이 글은 전반적으로 페이스북 메신저, 디스코드, 왓츠앱과 같은 실시간 메시징 애플리케이션의 시스템 설계를 설명하고 있습니다.
low-level 까지 완전히 동일하지는 않겠지만, 지난 개발경험동안 생각했던 구조들과 크게 다르지 않았고 이 구조들이 여러 곳에서 많이 사용된다고 느꼈습니다.
목차
전제조건 및 요구사항
1:1 채팅, 그룹 채팅, 채팅 기록 저장, 여러 기기 지원, 실시간 상태 업데이트 => 일반적인 챗, 메세징 시스템
(여러 기기에서 사용할 때 일관성을 높이고, 특히 낮은 지연시간이 중요)
- 일일 메시지 트래픽, 저장 요구사항 및 대역폭을 추산합니다.
- 이를 통해 서버와 스토리지 용량을 대략적으로 설정할 수 있습니다.
통신방법
통신 프로토콜에 대한 내용입니다.
사실 이 3가지 외에 또 다른 방식은 아는 것이 없었고 또 다른게 있을까 궁금했는데, 아쉬웠습니다.
가장 적합한 것은 역시 웹소켓 방식입니다.
- HTTP/HTTPS: 웹 기반 클라이언트에 적합하며 암호화가 쉬운 장점이 있지만, 서버에서 메시지를 즉시 보낼 수 없어 실시간성이 부족합니다.( ex : Restful API)
- 폴링 및 롱폴링: 사용 가능하지만 지연시간과 연결 관리 문제가 존재합니다.
- 웹소켓: 양방향 통신을 지원해 실시간으로 메시지를 주고받을 수 있어 서버가 즉시 업데이트를 푸시하는 데 적합합니다.
데이터베이스 선택
- 관계형 DB(ex: PostgresqlDB)는 사용자 프로필 저장에 사용하여 데이터의 일관성을 유지하고 복잡한 쿼리를 지원합니다.
- NoSQL (Key-Value 저장소)는 메시지 저장에 적합하며, 높은 읽기/쓰기 트래픽을 효율적으로 처리합니다.
Cassandra는 스케일링과 조정 가능한 일관성을 제공해 대규모 채팅 애플리케이션에 적합하다고 합니다..
설계 관점
- 로그인, 프로필 관리 등 사용자 관련 활동은 stateless로 처리합니다. (서버가 클라이언트의 상태나 세션을 유지하지 않고 요청을 독립적으로 처리한다는 뜻 입니다.)
- 상태를 유지하는 채팅 서비스: 지속적인 웹소켓 연결이 필요해 현재 채팅 세션 및 메시지 전달을 관리합니다.
조금더 들어가서 고려할게 있다면,,,
서버 부하, 위치, 용량, message flow 일텐데
- 1:1 채팅은 메시지 검증, 저장 및 즉시 전달을 포함합니다.
- 그룹 채팅은 메시지를 한 번만 저장하거나 구독 모델을 사용하여 중복 저장을 줄입니다.(참고로 구독 모델은 Pub/Sub 구조를 말하는 것입니다.)
웹소켓과 하트비트 메커니즘을 통해 온라인 상태를 유지하며,
네트워크의 일시적인 단절에도 상태가 빈번하게 변경되지 않도록 합니다.
이 방식이 조금 새롭게 느껴졌습니다.
웹소켓의 connection 에 대한 health check 개념인 것인데,
하트비트 메커니즘이라는 새로운 용어를 알게되어 좋습니다. (ping-pong 방식! 일정시간 텀을 둬서 세션이 살아있음을 확인, Django Channels에서는 연결이 끊어졌을 때 클라이언트 측에서 자동으로 재연결을 시도함.)
최적화와 결함에 대한 대비!
- 그룹 채팅에서 메시지를 푸시/풀 방식으로 관리하여 중복을 줄입니다.
- 채팅 서버 간의 느슨한 결합과 병렬 처리를 위해 메시지 큐를 사용합니다.
- 데이터 복제, 로드 밸런싱, 서킷 브레이커 및 장애 전환 메커니즘을 통해 시스템의 회복력을 높이고 중복성을 제공합니다.
성능 고려
여기까지는 채팅과 메세징에 대한 설계관점을 다양하게 다뤘다면, 조금 더 매지닝레벨로 들어가면 성능과 확장성 측면에서 고려하게될 시점이 분명 올 것 입니다.
그 때는 아래와 같은 사항들을 고려하는 것이 좋을 것 같습니다.
- 캐싱, 비동기 처리, API 최적화(페이지네이션, 필터링) 및 수평 확장을 통해 성능을 유지합니다.
- 네트워크 파티션 상황에서도 데이터 일관성을 유지하는 것을 우선시하고, 가용성은 약간 타협하는 설계를 채택합니다.
이 설계는 실시간 성능, 확장성, 내결함성, 일관성을 잘 균형 잡아 높은 트래픽과 낮은 지연이 요구되는 메시징 애플리케이션의 핵심 과제를 해결합니다.
레퍼런스 링크
https://medium.com/@ishwarya1011.hidkimath/system-design-design-a-chat-system-e0056fb093d1
'Develop' 카테고리의 다른 글
데이터베이스 정규화 이해하기 (1) | 2024.11.17 |
---|---|
pytest로 이해하는 팩토리함수 (1) | 2024.11.16 |
Vercel 404 오류 해결하기 - 간단한 Rewrite 설정 (1) | 2024.10.08 |
Nextjs에서 tag cloud 사용하기 (2) | 2024.09.21 |
Nextjs<Image />에서 remotePatterns로 외부 이미지 사용하기 (0) | 2024.09.18 |