https://product.kyobobook.co.kr/detail/S000001033116
가상 면접 사례로 배우는 대규모 시스템 설계 기초 | 알렉스 쉬 - 교보문고
가상 면접 사례로 배우는 대규모 시스템 설계 기초 | “페이스북의 뉴스 피드나 메신저,유튜브, 구글 드라이브 같은 대규모 시스템은 어떻게 설계할까?” IT 경력자라도 느닷없이 대규모 시스템
product.kyobobook.co.kr
1장 사용자 수에 따른 규모 확장성 : https://inhyeok-blog.tistory.com/40
2장 개략적인규모추정 : https://inhyeok-blog.tistory.com/41
3장 시스템 설계 면접 공략법 : https://inhyeok-blog.tistory.com/42
4장 처리율제한장치의설계 : https://inhyeok-blog.tistory.com/43
5장 안정해시설계 : https://inhyeok-blog.tistory.com/44
6장 키-값저장소설계 : https://inhyeok-blog.tistory.com/45
7장 분산시스템을위한유일 ID 생성기설계 : https://inhyeok-blog.tistory.com/46
8장 URL 단축기설계 : https://inhyeok-blog.tistory.com/47
9장 웹크롤러설계 : https://inhyeok-blog.tistory.com/48
10장알림시스템설계 : https://inhyeok-blog.tistory.com/49
11장뉴스피드시스템설계 : https://inhyeok-blog.tistory.com/50
12장채팅시스템설계 : https://inhyeok-blog.tistory.com/51
13장검색어자동완성시스템 : https://inhyeok-blog.tistory.com/52
14장유튜브설계 : https://inhyeok-blog.tistory.com/53
15장구글드라이브설계 : https://inhyeok-blog.tistory.com/54
요구사항
- 1:1채팅, 그룹 채팅 모두 지원
- 웹/앱 모두 지원
- DAU는 5천만명
- 그룹 채팅 최대 인원은 100명
- 사용자의 접속상태를 표시해야함
- 메시지 길이는 100,000자 이하여야 한다.
- 채팅 이력은 영원히 보관해야 한다.
채팅 프로토콜
채팅 서비스는 메시지 송신 클라언트로부터 메시지를 받아서 저장하고, 메시지 수신 클라이언트에게 메시지를 전달해야 한다. 이를 위해 어떤 프로토콜을 사용할지 살펴보자.
- 폴링
폴링은 주기적으로 수신 클라이언트가 서버에게 새 메시지가 있는지 물어보는 방식이다 . 이 방식은 서버 자원 불필요하게 낭비된다는 단점이 있다.
- 롱 폴링
폴링의 단점을 완화하기 위해서 새 메시지가 반환되거나 타임아웃 될 때까지 연결을 유지하는 방식이다. 이 방식은 수신 클라이언트와 송신 클라이언트가 다른 서버에 접속할 수도 있다는 문제가 있다. 또한 서버 입장에서 클라이언트가 연결을 해제했는지 아닌지 알 방법이 없다. 그리고 무엇보다 여전히 비효율적이다.
- 소켓
웹소켓은 서버가 클라이언트에게 비동기 메시지를 보낼 때 가장 널리 사용하는 기술이다. 웹 소켓은 HTTP 기반의 방식들과 달리 클라이언트가 시작한다. 한번 맺어진 연결을 항구적이며 양방향이다. 웹 소켓을 이용하면 메시지를 보낼 때나 받을 때 동일한 프로토콜을 사용할 수 있으므로 설계와 구현이 단순하고 직관적이다. 다만 웹소켓 연결은 항구적으로 유지되어야 하기 때문에 서버 측에서 연결 관리를 효율적으로 해야 한다.
개략적인 설계
개략적인 설계는 무상태 시스템, 상태 유지 시스템, 제 3자 서비스 연동 시스템으로 나눌 수 있다.
- 무상태 서비스
무상태 서비스는 일반적인 API서버와 동일하게 로그인, 회원가입, 사용자 프로파일 표시 등을 처리한다.
- 상태 유지 서비스
채팅 서버는 상태 유지가 필요하다. 이는 클라이언트가 채팅 서버와 독립적인 네트워크 설정을 유지해야 하기 떄문이다.
- 제 3자 서비스 연동
제 3자 서비스는 푸시 알림이다. 새 메시지를 받았다면 앱이 꺼져 있어도 알람이 와야 할 것이다.
- 규모의 확장성
SPOF를 막기 위해서라도 규모의 확장성을 고려하는 것은 필수적이다. 위의 언급된 요소들을 하나로 묶으면 다음과 같은 개략적인 설계안이 나온다. (키-값 저장소에는 채팅 이력을 보관한다.)
- 저장소
사용자 프로파일/설정/친구 목록 처럼 일반적인 데이터는 RDB에 보관하면서 다중화와 샤딩과 같은 기술을 고려한다.
채팅 이력 데이터는 키-값 저장소를 사용한다. 이를 이해하려면 채팅 이력 데이터의 읽기/쓰기 연산 패턴을 이해 해야 한다.
1. 채팅 이력 데이터는 양이 많다.(페북 메신저는 매일 600억개의 메시지를 처리한다)
2. 최근 주고받은 데이터를 주로 본다. 오래된 메시지는 잘 보지 않는다.
3. 검색 기능, 특정 사용자 언급 메시지, 특정 메시지로 점프 등의 기능을 위해 무작위 데이터 접근하는 기능도 지원해야한다.
4. 1대1채팅 앱의 경우 읽기:쓰기 비율은 대략 1:1이다.
이런 특징을 모두 지원하기 위해 키-값 저장소를 사용하는데 그 이유는 다음과 같다.
1. 수평적 규모확장이 쉽다.
2. 접근 지연시간이 낮다.
3. RDB는 롱 테일에 해당하는 부분을 잘 처리하지 못한다. 또한 인텍스가 커지면 데이터 무작위 접근 비용이 증가한다.
4. 이미 많은 채팅 시스템이 키-값 저장소를 사용한다.
- 데이터 모델
키-값 저장소를 사용하기로 했으니 이제 메시지 데이터를 어떤 형태로 보관할 것인지 살펴보자. 왼쪽은 1:1 메시지를 저장할 떄 사용하는 테이블이고, 오른쪽은 그룹 메시지를 저장할 때 사용할 테이블이다.
message_id는 다음과같은 조건을 만족해야 한다.
- 고유해야한다.
- ID값은 정렬 가능해야 하며 시간 순서와 일치해야 한다.
이를 위한 전략은 앞서 살펴본 SnowFlake와 같은 방식과 지역적 순서 번호 생성기를 이용하는 것이다. 여기서 지역적 순서 번호 생성기는 ID의 유일성은 같은 그룹 안에서만 보증하면 충분하는 것이다.
상세 설계
이제 상세 설계를 살펴보자
서비스 탐색(상세 설계)
서비스 탐색 기능의 주된 역할은 클라이언트에게 가장 적합한 채팅 서버를 추천해 주는 것이다. 이때 위치, 서버 용량 등을 기준으로 선택한다. 이를 위해 아파치 주키퍼와 같은 오픈소스를 사용할 수 있다. 서비스 탐색은 다음과 같이 동작한다.
메시지 흐름(상세 설계)
1.1:1 채팅 메시지 처리 흐름
2. 여러 단말 사이의 메시지 동기화
채팅은 모바일, 데스크톱, 테블릿 등의 다양한 단말에서 사용할 수 있다. 각 단말을 동기화 하는 방식은 다음과 같은 방식으로 이루어 진다.
채팅 서버에서는 사용자의 모든 단말에 대한 웹 소캣 연결을 유지한다. 그리고 각 단말은 본인이 읽어온 가장 최신 메시지의 ID를 가지고 있다. 이제 각 단말에 접근했을 때 다음과 같은 2가지 조건을 만족하는 메시지는 새 메시지로 간주한다.
- 수신자 ID가 현재 로그인한 사용자 ID와 같다.
- 키-값 저장소에 보관된 메시지로서, 그 ID가 cur_max_message_id보다 크다.
- 소규모 그룹 채팅에서의 메시지 흐름
현재 요구사항은 그룹채팅이 500명까지 가능하므로, 소규모라고 볼 수 있다. 이를 위해서는 메시지 큐를 사용자 단말마다 하나씩 생성해서 두고, 송신 측에서 보내야 하는 사용자에게 넣어주면 된다.
이 방식은 소규모 그룹 채팅에서 적합한데 그 이유는 새 메시지를 확인하기 위해 자기 큐만 보면 되니까 동기화가 쉽고, 그룹이 크지 않다면 메시지를 수신자별로 복사해서 큐에 넣는 작업의 비용이 크지 않기 때문에 좋다.
접속상태 표시(상세 설계)
클라이언트와 실시간 서비스 사이에 웹소켓 연결이 맺어지고 나면 접속상태 서버는 A의 상태와 last_active_at 타임스탬프 값을 키-값 저장소에 보관한다.이로서 해당 사용자는 접속 중으로 표시 될 것이다.
로그 아웃은 단순히 키-값 저장소에 저장소에 보관된 사용자 상태가 online에서 offline으로 변경되면 된다.
- 접속 장애
네트워크 환경은 언제가 가용하지 않는다. 예컨데 터널만 들어가도 그렇다. 그래서 x초 이상 통신이 되지 않는 경우에만 접속상태를 offline으로 변경해야 한다. 이를 위해서 저자는 박동(heartbeat)검사를 제안한다. 즉, 온라인 상태의 클라이언트로 하여금 주기적으로 박동 이벤트를 서버로 보내고, 마지막 이벤트를 받은 지 x초가 지나도 다음 박동 이벤트가 오지 않으면 오프라인으로 바꾸는 것이다.
- 상태 정보의 전송
발행-구독 모델을 사용해서 사용자의 상태 변화를 알릴 수 있다. 이는 친구관계당 하나씩 채널을 두는 것으로 하면 된다. 이 방법은 그룹의 크기가 작을 때 효과적이다. 하지만 그룹 크기가 커지면 이런 식으로 접속 상태 변화를 알려서는 비용이나 시간이 많이 들게 되므로 좋지 않다.
근데 왜 친구관계당 하나씩 두는지는 잘 이해되지 않는다. 사용자당 하나의 채널을 만들어두고, 구독자를 여러명 두면 되는 것 아닌가? 메시지가 소비되는 것이 문제라면 메시지에 읽어야 하는 사용자 수를 기록해 두고 한명의 사용자가 읽을 때마다 1씩 감소시켜서 0이 되면 메시지를 최종적으로 삭제하도록 할 수는 없는것인가? 혹시 동시성 문제가 걱정되는 것인가?
'책 리뷰' 카테고리의 다른 글
[가상 면접 사례로 배우는 대규모 시스템 설계 기초]14. 유튜브 설계 (0) | 2023.05.22 |
---|---|
[가상 면접 사례로 배우는 대규모 시스템 설계 기초]13. 검색어 자동완성 시스템 (0) | 2023.05.22 |
[가상 면접 사례로 배우는 대규모 시스템 설계 기초]11. 뉴스 피드 시스템 설계 (1) | 2023.05.19 |
[가상 면접 사례로 배우는 대규모 시스템 설계 기초]10. 알림 시스템 설계 (1) | 2023.05.18 |
[가상 면접 사례로 배우는 대규모 시스템 설계 기초]9. 웹 크롤러 설계 (1) | 2023.05.18 |