Published on

2. 주변 친구 찾기

Authors
  • avatar
    Name
    이건창
    Twitter

결론 : 아키텍처를 단순하게 만든다면 더 많은 메모리를 투입할 만한 가치가 충분하다.

1 단계 : 문제 이해 및 설계 범위 확장

설계 범위 좁히기

  • 서비스 기준
    • 주변은 얼만큼의 거리인지, 직선거리인지?
    • 사용자 수는?
    • 사용자의 이동 이력을 저장해야 하는지?
    • 친구가 비활성화면 주변 친구 목록에서 안보여야할지?

요구사항 정제

  • 요구사항 정제
    • 사용자는 주변 친구를 확인할 수 있다.
    • 주변친구가 마지막에 있었던 위치, 거리, 시각을 확인할 수 있다.
    • 주변 친구 목록은 초 단위로 갱신된다.
  • 비기능 요구사항 정제
    • 낮은 지연 시간을 목표한다.
    • 시스템 안정성을 목구한다.
    • 결과적 일관성을 목표한다.

결과적 일관성은 고가용성을 달성하기 위한 일관성 모델로 조회하는 현재가 모든 업데이트가 완료된 시점이고 마지막으로 업데이트 된 값임을 보장하는 방식이다.

개략적 규모 추정

  • 주변 친구는 8km 반경으로 정의한다.
  • 주변 친구 위치 정보 갱신은 30초 주기로 갱신한다.
  • 매일 주변 친구를 검색하는 DAU는 1억 명으로 가정한다.
  • 동시 접속 사용자 수는 DAU의 10%로 가정한다.
  • 한 사용자는 평균 400명의 친구를 갖는다.

2 단계 : 개략적 설계안 제시 및 동의 구하기

2단계에서는 다음 내용을 설명한다.

  • 개략적 설계
  • API 설계
  • 데이터 모델

개략적 설계

사용자는 활성화된 주변 친구 정보를 수신하고자 하고 자신의 위치를 활성화된 주변 친구에게 전달하고 싶어한다. 그럼 순수한 P2P 방식으로 주변 친구와 항구적인 통신 상태를 유지하면 된다.

다만 P2P 방식의 단점은 주변과의 통신 연결 상태에 따라 서비스 품질이 결정되고 주변 친구가 늘어나면 통신해야 하는 기기가 늘어나 전력이 많이 든다는 점이 있다.

그림 1

중간 서버에서 모든 활성 상태 사용자의 변화 내역을 수신하고 주변 친구에게 정보를 전달하면 된다. 생각보다 간단해보이지만 동시 접속자 수가 많아지면 그에 맞게 서버를 증설해야 한다. 중간 서버에서 동시 접속자 수를 관리하기 위해 필요한 건 웹 소켓 프로토콜, pub/sub 서버로 볼 수 있다.

웹 소켓 프로토콜은 TCP 접속에 전이중 통신을 지향하는 통신 프로토콜이다. 주변 친구들의 정보를 지속적으로 받기 위해 PUSH 를 받을 수 있어야 한다.

pub/sub 서버는 메시지 생성과 처리를 분리하기 위한 목표를 가진다. 사용자의 채널을 생성해 주변 친구들에게 메시지를 전달하는 역할을 하게 된다. 구독하려면 쉽게 구독이 가능하다.

그림 2

처음 접속하게 되면 주변 친구 정보를 찾아 친구들의 채널을 구독한다.

그림 3

전송과 전달은 간단하다. 다음처럼 작업하면 된다. 데이터베이스에 위치 이력을 저장하는 이유는 단순 요구사항을 만족하기 위해서다.

그림 4

API 설계

주변 위치 친구 찾기에 필요한 API는 다음과 같다.

  • 서버 API
    • 주기적인 위치 정보 갱신 API
    • 웹소켓 초기화 API
  • 클라이언트 API
    • 갱신된 친구 위치를 수신할 API
    • 새 친구 구독 API
    • 구독 해지 API

데이터를 실시간 추적하고 전달해야하는 곳에 초점을 맞추기 위해 그 밖 내용은 생략한다.

3 단계 : 상세 설계

주요 구성 요소 별 규모 확장성을 고려해야 하는데 그 중 웹 소켓pub/sub 서버 기준으로 살펴보겠다.

  • 웹소켓 서버
    • 웹소켓 서버는 유상태 서버라 제거하는 행위를 주의해야 한다. 간단하게 로드밸런서가 종료하기 전 연결 종료 중 상태로 변경하고 모든 연결이 종료되면 서버를 내릴 수 있도록 하면 쉽게 해결 가능하다.
  • pub/sub 서버
    • 해당 설계에서 pub/sub 서버를 라우팅 계층으로 활용한다. pub/sub 서버를 사용하는 이유는 채널 관리 비용이 저렴하기 때문이다.

주변 친구 기능을 활용하는 모든 사용자에게 채널을 하나씩 부여하고 서비스 시작시 친구의 상태 관계 없이 친구들의 모든 채널을 구독한다. 어차피 비활성화된 친구는 채널에 알람이 안오기 때문이다. 그럼 상태마다 관리해야 하는 작업량이 줄어든다.

  • pub/sub 클러스터
    • 각 채널은 독립적이기 때문에 분산하기 어렵다. 그렇기에 서비스 탐색(service discovery)컴포넌트를 사용해 문제를 해결 할 수 있다. etc, zookeeper를 사용하면 된다. 별거 없다. 해시 링을 사용하고 pub/sub 서버에서 발생하는 변경 내역에 맞춰 클라이언트 정보를 수정하면 된다.
  • pub/sub 클러스터 고려사항
    • pub/sub 클러스터는 채널에 대한 상태 정보를 보관하기 때문에 상태를 가진다고 볼 수 있다. 그렇기에 변경이 어려우므로 여우가 있을 때 오버 프로비저닝을 해야 한다.

그 밖에 엣지케이스는 두 개 정도 존재하고 책에 설명이 잘되어 있으니 패스한다.

  • 친구가 많은 사용자
  • 주변의 임의 사용자

4 단계 : 마무리