대규모 시스템 설계 기초 2 (2장)
가상 면접 사례로 배우는 대규모 시스템 설계 기초 2 (2장) 의 내용 중, 인상적이었던 부분을 발췌 및 요약합니다.
주변 친구
기본 아키텍쳐
모바일 사용자는 로드 밸런서를 통해서 웹소켓 서버 또는 api 서버와 통신한다. 웹소켓 서버를 통해서 양방향 위치 정보를 수신할 수 있을 것이다.
검색 반경 내 친구 위치가 변경되면 해당 내역은 이 연결을 통해 클라이언트로 전송된다. 이 때, redis 를 사용할 수 있다. redis 는 활성 상태 사용자의 최근 위치 정보를 캐시한다. redis 펍/섭은 경량 메시지버스이다. 사용자들이 위치 정보가 갱신됏다는 이벤트를 pub 하면, 레디스를 통해서 적합한 수신자는 이를 수신한다.
클라이언트 초기화
모바일 클라이언트는 기동되면 웹소켓 클러스터 내의 서버 가운데 하나와 지속성 웹소켓 연결을 맺는다. 연결에는 많은 메모리를 필요로 하지 않고, 연결이 초기화되면 클라이언트는 해당 모바일 단말의 위치를 서버로 전송할 것이다.
웹소켓 서버는 각 친구의 레디스 서버 펍/섭 채널을 구독한다. 채널 생성 및 구독 비용이 저렴하므로 친구의 활성화/비활성화 상태에 관계없이 모든 채널을 구독할 수 있다.
위치 정보 캐시
사용자의 실시간 위치 정보는 레디스 서버에 캐시할 수 있다. 위치 정보 보관에 필요한 데이터는 약 100 바이트 정도니 천만 명의 사용자더라도, 수 GB 이상의 메모리를 가진 서버 한대로 모든 위치 정보를 캐시할 수 있을 것이다.
다만, 갱신 연산의 수가 부담스러울 수 있으니 샤딩을 고려해보자. 사용자 ID 를 기준으로 한다면 부하를 고르게 분산할 수 있을 것이다.
레디스 펍/섭 서버
레디스 펍/섭을 선택한 이유는 채널을 만드는 비용이 아주 저렴하기 때문이다. 새 채널은 구독하려는 채널이 없을 때 생성한다. 구독자가 없는 채널로 전송되는 메시지는 그대로 버려지는데, 그 과정에서 서버의 부하는 없다.
채널 하나를 유지하기 위해서는, 구독자 관곌르 추적하기 위한 해시 테이블과 연결 리스트만 필요하다.
메모리 사용량은?
10억 사용자의 10% 인 1억 사용자면 채널이 1억개가 필요할 것이다. 활성화 친구 가운데 100 명이 주변 친구 기능을 사용하고, 이러한 매핑을 위해 20 바이트의 포인터를 저장해야 한다고 가정하자. 그러면 1억 * 20바이트 * 100명의 친구니 약 200G 의 메모리가 필요할 것이다.
CPU 사용량은?
초당 1400 만건의 위치 정보 업데이트를 해야 하는 상황이다. 레디스 서버 한 대가 감당 가능한 구독자의 수가 얼마일지는 네트워크 트레픽과 CPU 성능에 따라 차이가 있을 것이다. 보수적으로 약 10만건을 처리할 수 있다고 가정하면 140 대가 필요할 것이다.
분산 레디스 펍/섭 클러스터
레디스 펍/섭 서버는 메시지를 발행할 채널이나 구독할 채널을 정해야 할 때 이 해시 링을 참조한다.
- 웹소켓 서버는 해시 링을 참조하여 메시지를 발행할 레디스 펍/섭 서버를 선정한다.
- 웹소켓 서버는 해당 서버가 관리하는 사용자 채널에 위치 정보 변경 내역을 발핸한다.
펍/섭 서버는 채널에 대한 상태 정보를 보관하는 유상태 서버 클러스터이다. 각 채널의 구독자 목록은 그 상태 정보의 핵심적 부분이다.
해시 링이 갱신된다면, 재구독 요청이 발생할 수 밖에 없다. 재구독 요청을 처리하다보면 클라이언트가 보내는 위치 정보 변경 메시지의 처리가 누락될 수 있다.