본문으로 건너뛰기

Chatting

1 Chatting

  • 채팅 서비스는 크게 세 가지 핵심 부분으로 구성됩니다
    • HTTP API Server
    • 채팅 서버(접속 상태 서버)
    • 푸시 알림 서버

1.1 HTTP API Server

  • API 서버는 로그인, 등록, 사용자 프로필 표시와 같은 전통적인 요청/응답 작업을 관리하는 무상태 서비스로 운영됩니다.
  • 로드 밸런서 뒤에 위치하며, 사용자 상태 정보를 유지하지 않고 사용자 요청을 효율적으로 처리합니다.

1.2 채팅 서버(접속 상태 서버)

  • API 서버와 달리 채팅 서버는 상태를 유지하며, 각 클라이언트가 지속적인 네트워크 연결을 유지합니다.
  • 이 설계는 클라이언트가 동일한 서버에 지속적으로 연결되어 있도록 하여 메시지 일관성과 실시간 통신 기능을 향상시킵니다.
  • 서버는 로드를 분산하고 연결 라우팅을 효과적으로 관리하기 위해 서비스 발견 메커니즘(예: Apache Zookeeper)을 활용합니다.

1.3 푸시 알림 서버

  • 푸시 알림 서버는 사용자가 오프라인이거나 비활성 상태일 때 메시지를 전달하는 데 있어 중요합니다.
  • 이를 통해 사용자가 새 메시지와 참여에 대해 계속 정보를 받을 수 있도록 하여 전반적인 사용자 경험을 향상시킵니다.

2 저장소

  • 채팅 서비스의 데이터 저장소는 사용자 관련 데이터를 위한 관계형 데이터베이스와 채팅 내역 및 메시지를 처리하기 위한 NoSQL 데이터베이스의 조합입니다.
  • 이 접근법은 데이터 무결성, 확장성 및 빠른 접근을 위한 최근 및 자주 사용되는 정보의 균형을 맞춥니다.
  • 사용자 프로파일, 설정, 친구 목록과 같은 데이터는 안정성을 보장하는 관계형 데이터베이스에 저장
  • 채팅 시스템 고유의 데이터 즉 채팅 이력은 어디에 저장할 것인가?
    • 채팅 이력 데이터는 양은 엄청나다.
    • 이 데이터 중 빈번하게 사용된ㄴ 것은 최근 메시지이다.
    • 검색 기능을 사용해 특정 사용자가 언급된 메시지를 보거나 특정 메시지로 점프하는 무작위적인 데이터 접근을 하기도 한다.
    • 1:1 채팅의 경우 읽기 쓰기 비율이 대략 1:1이다

3 데이터 모델

  • 채팅 시스템의 데이터 모델은 메시지의 고유성과 적절한 시간 순서를 보장하면서 일대다 통신 시나리오를 효과적으로 처리할 수 있어야 합니다

3.1 메시지 ID

  • 메시지 ID가 충족해야할 조건
    • ID는 고유해야 한다.
    • 정렬 가능해야 하며 시간 순서와 일치해야 한다.
      • 즉 새로운 ID는 이전 ID보다 큰 값이어야 한다.
  • [[Unique-Id-Generator]] 참고

4 흐름

4.1 서비스 탐색 과정

  • 서비스 탐색이란 클이언트에게 가장 적합한 채팅 서버를 추천해주는 것이다.
  • 주로 클라이언트의 위치, 서버의 용량을 기준으로 탐색한다.
  • 오픈 소스 솔루션으로 아파치 주키퍼가 있으며 사용 가능한 채팅 서버를 주키퍼에 등록하고 클라이언트가 접속을 시도하면 사전에 정한 기준에 따라 최적의 채팅 서버를 골라 주면 된다.

서비스 탐색 과정

  1. 사용자 A가 시스템에 로그인을 시도한다.
  2. 로드밸런서가 로그인 요청을 API 서버 중 하나로 보낸다.
  3. API 서버가 로그인을 처리하고 서비스 탐색 기능을 동작해 사용자가 사용할 최적의 채팅 서버를 찾아 사용자에게 반환한다.
  4. 사용자 A는 반환 받은 채팅 서버와 웹소켓 연결을 맺는다.

4.2 메시지 처리 과정

  1. 사용자가 채팅 서버 1에 메시지 전송
  2. 채팅 서버 1은 ID 생성기를 통해 해당 메시지의 ID를 결정
  3. 채팅 서버 1은 해당 메시지를 메시지 동기화 큐로 전송
  4. 메시지 동기화 큐에서 키-값 저장소로 메시지 보관됨
  5. 메시지 동기화 큐에서 메시지는
    1. 사용자 B가 접속중이면 채팅 서버 2로 전송됨
    2. 사용자 B가 접속중이 아니면 메지시를 푸시 알림 서버로 보냄
  6. 채팅 서버 2는 메시지를 사용자 B에게 전송한다.
    1. 사용자 B와 채팅 서버 2 사이에는 웹소켓이 연결되어 있는 상태

4.3 여러 단말 사이 메시지 동기화 과정

  • 사용자 A의 전화기와 랩톱 두 대의 단말을 사용하고 있다.
  • 각 단말은 cur_max_message_id라는 변수를 유지한다.
    • 해당 단말에서 관측된 최신 메시지 ID를 담고있다.
    • 단말마다 별도로 유지 관리되는 값이다.
  • 아래의 두 조건을 만족하면 새로운 메시지로 간주한다.
    • 수신자 ID가 현재 로그인한 사용자 ID와 같다.
    • 메시지의 ID가cur_max_message_id보다 크다.

4.4 접속상태 표시 과정

  • 사용자가 API 서버를 통해 로그인하고 클라이언트와 접속상태 서버와 웹소켓 연결이 맺어지면 접속상태 서버는 A의 상태와 lastActiveAt 타임 스탬프 값을 키-값 저장소에 보관한다.
  • 이 절차가 끝나면 해당 사용자는 접속 중인 것으로 표시된다.
  • 사용자가 API 서버를 통해 로그아웃하면 API 서버는 접속상태 서버에 요청을 보내 키-값 저장소에 보관된 사용자 상태가 online에서 offline으로 바뀌게 된다.

접속 장애

  • 인터넷을 통한 연결은 불안정하다.
  • 사용자의 인터넷 연결이 끊어지면 클라이언트와 서버 사이에 맺어진 웹소켓 같은 지속성 연결이 끊어진다.
  • 이런 장애의 대응 방법은 사용자를 오프라인 상태로 표시하고 연결이 복구되면 온라인 상태로 변경하는 것이다.
  • 하지만 이런 방법은 문제가 많다.
    • 짧은 시간동안 인터넷 연결이 끊어졌다 복구되는 일은 흔하다.
  • 따라서 heartbeat 검사를 통해 이 문제를 해결한다.
  • 주기적으로 클라이언트가 heartbeat event를 접속 상태 서버로 보내고 마지막 이벤트를 받은 지 X초 이내에 또 다른 heartbeat event를 보내면 해당 사용자의 접속상태를 계속 온라인으로 유지하는 것이다.