본문 바로가기

인프라/ACC project

대규모 시스템 설계 기초(12장 발췌독)

 

 

위 책에서는 페이스북 메신저와 유사한 채팅 앱을 설계하고자 함 

요구 사항은 다음과 같다 

 

- 1:1채팅, 그룹 채팅 앱 둘다 지원 

- 모바일 앱, 웹 앱 둘 다 지원 

- DAU(Daily Active User) 기준으로 5천만명 처리 가능

- 그룹 채팅 최대 100명

- 1:1 채팅, 그룹 채팅, 사용자 접속상태 표시, 텍스트 메시지만 주고 받을 수 있다 

- 메시지 길이에 제한 : 100,000 자 이하

- 채팅 이력은 영원히 보관

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

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

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

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

- 푸시 알림 

 

채팅 서비스는 아래 기능을 제공해야 한다 

- 클라이언트들로부터 메시지 수신

- 메시지 수신자 결정 및 전달

- 수신자가 접속(online) 상태가 아닌 경우에는 접속할 때까지 해당 메시지 보관 

 

클라이언트와 채팅서비스의 관계도를 그림으로 보여주면 다음과 같다 

 

sender는 오랜 세월 검증된 HTTP 프로토콜을 사용한다.

채팅 서비스와의 접속에는 keep-alive 헤더를 사용하면 클라이언트,서버 사이 연결을 끊지 않고 유지할 수 있어 효율적

Receiver 시나리오는 더욱 복잡한 과정이다. 서버에서 클라이언트에게 메세지를 보내는 데에 많은 기법이 제안되어 왔다

 

1. 폴링 

- 서버 자원이 불필요하게 낭비된다는 문제

2. 롱 폴링(long polling)

- HTTP 서버들은 보통  무상태 서버이기에 round robin 알고리즘을 사용하는 경우, 메시지를 받은 서버는 해당 메시지를 수신할 클라이언트와의 롱 폴링 연결을 가지고 있지 않은 서버일 수 있다

- 서버 입장에서는 클라이언트가 연결을 해제했는지 아닌지 알 좋은 방법이 없다

 

3. 웹소켓

- 서버가 클라이언트에게 비동기 메시지를 보낼 떄 가장 널리 사용하는 기술이다 

- 웹소켓은 일반적으로 방화벽이 있는 환경에서도 잘 동작한다.

- 80이나 443처럼 HTTP, HTTPS 프로토콜이 사용하는 기본 포트번호를 그대로 쓰기 때문이다 

 

 

여기서 알아둬야하는 점은 사실 대부분의 기능(회원가입, 로그인, 사용자 프로파일 등) 일반적은 HTTP 상에서 구현해도 된다 

이 책에서 구현하는 채팅 서비스는 무상태 서비스, 상태유지(stateful) 서비스, 제3자 서비스 연동의 세 부분으로 나누어 살펴볼 수 있다 

 

무상태  서비스

- 로그인, 회원가입, 사용자 프로파일 표시 등을 처리하는 전통적이니 요청/응답 서비스 

- 로드 밸런서 뒤에 위치한다 

- 로드 밸런서 뒤에 오는 서비스는 모놀리틱 서비스(모놀리틱 아키텍처란 비즈니스 로직, DB, UI 등을 하나의 패키지에 담아 빌드하고 배포하는 아키텍처)일 수도 있고, 마이크로서비스(하나의 큰 애플리케이션을 여러 개의 작은 애플리케이션으로 쪼개어 변경과 조합이 가능하도록 만든 아키텍처)일 수 있다 

 

상태 유지 서비스 

- 유일하게 상태 유지가 필요한 서비스는 채팅 서비스이다

- 각 클라이언트가 채팅 서버와 독립적인 네트워크 연결을 유지해야 한다 

 

제3자 서비스 연동

- 채팅 앱에서 가장 중요한 제3자 서비스는 푸시 알림이다

 

트래픽의 양이 적더라도 모든 것을 한 대의 서버에 담은 설계안은 좋지 못한데, 그 이유 중 하나는 SPOF(동작하지 않으면 전체 시스템의 문제) 포함된다 

 

위에 언급된 내용을 모두 반영한 개략적 설계안은 다음과 같다

 

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

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

- API 서비스는 로그인, 회원가입, 프로파일 변경 등 그 외 나머지 처리 

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

- key-value DB에 채팅 이력을 보관한다 

 

저장소

일반적인 데이터(프로파일, 설정, 친구 목록)

- 관계형 데이터베이스에 보관한다

- 다중화(하나의 고속 통신 회선을 다수의 단말기가 공유할 수 있도록 하는 것)와 샤딩(데이터를 조각내 분산 저장하는 데이터 처리 기법)

고유한 데이터(채팅 이력)

- 키-값 저장소는 수평적 규모확장(horizontal scalling)이 쉽다 

- 키-값 저장소는 데이터 접근 지연시간(latency)이 낮다

- 페이스북 메신저나 디스코드 또한 키-값 저장소를 채택했다

 

데이터모델

1:1 채팅을 위한 메시지 테이블 

그룹 채팅을 위한 메시지 테이블 

 

 

message_ id는 고유해야 하는데, 이는 정렬 가능해야하며 결국 시간 순서와 일치해야 한다 

NoSQL은 auto_increment를 제공하지 않기에 전역적 64-bit 순서 번호 생성기나 지역적 순서 번호 생성기(그룹 안에서만 유일성 보증) 등을 사용해야 한다 

 

서비스 탐색

- 서비스 탐색 기능의 주된 역할은 클라이언트에게 가장 적합한 채팅 서버를 추천하는 것이다 

- 이때 사용되는 기준으로는 클라이언트의 위치, 서버 용량 등이 있다 

사용자A 로그인 -> 로드밸런서가 로그인 요청을 API 서버들 가운데 하나로 보낸다 -> API 서버가 사용자 인증을 처리하고 나면 서비스 탐색 기능이 동작하여 해당 사용자를 서비스할 최적의 채팅 서버를 찾는다 -> 선택된 서버와 웹소켓 연결을 맺는다

 

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

 

A가 채팅 서버1로 메시지 전송 -> ID 생성기를 사용해 해당 메시지의 ID 결정 -> 해당 메시지를 메시지 동기화 큐로 전송 -> 메시지가 키-값 저장소에 보관됨 -> B가 접속 중인 경우 메시지가 채팅서버 2로 전송됨 or B가 접속 중이지 않은 경웅, 푸시 알림 메세지를 푸시 알림 서버로 보냄 -> 채팅 서버2는 메시지를 사용자 B에게 전송(웹소켓 연결이 있는 상태)

 

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

 

상황예시) 

A가 채팅방에 메시지를 보냄 -> 보낸 메세지가 B,C의 메시지 동기화 큐에 복사됨 

위 구조는 소규모 그룹 채팅에 적합(메시지 동기화 플로우의 단순함과 작업 비용이 저렴함)-> WeChat이 위와 같은 접근사용

 

다른 효율적인 방식으로는 메시지 동기화 큐(여러 사용자로부터 오는 메세지를 받을 수 있다)

 

 

접속상태 표시 

- 접속상태 표시를 위해 접속상태 서버를 사용하는데, 이는 클라이언트와 웹소켓으로 통신하는 실시간 서비스의 일부

 

사용자 로그인/로그아웃

- 클라이언트와 실시간 서비스 사이에 웹소켓 연결이 맺어지고 나면 접속상태 서버는 A의 상태와 last_active_at 타임스탬프 값을 키-값 저장소에 보관

 

- 로그아웃은 키-값 저장소에 보관된 사용자 상태가 online에서 offline으로 바뀌게 된다는 점

 

접속장애

- heartbeat 검사를 통해 문제해결 (주기적으로 박동 이벤트를 접속상태 서버로 보내고, x초 이내에 또 다른 heartbeat 이벤트 메시지를 받지 못하면 오프라인으로 바꾸는 것)

 

 

상태 정보의 전송

- publish-subscribe model을 사용하여 각각의 친구관계마다 채널을 하나씩 두는 것

- 그룹 크기가 작을 때는 효과적

 

'인프라 > ACC project' 카테고리의 다른 글

해커톤을 준비하며  (0) 2024.07.28
1차 회의를 마치며  (0) 2024.07.21