채팅 시스템 설계

bw1611·2024년 3월 1일

통신 프로토콜 : HTTP

클라이언트가 채팅 서비스에 HTTP 프로토콜로 연결 후 채팅 접속 시 keep-alive 헤더를 사용한다. keep-alive를 활용하면 TCP 접속 과정에서 발생하는 핸드셰이크 횟수를 줄일 수 있다.

단점으로는 수신 시나리오가 복잡하며 서버에서 클라이언트로 임의 시점에 메시지를 전달하는데 쉽게 쓰일 수 없다.

보안 기법

  • 폴링
  • 롤 폴링
  • 웹 소켓

폴링

폴링은 클라이언트가 주기적으로 서버에게 새 메시지가 있는지 물어보는 방식, 폴링을 자주할 수록 비용이 증가하며, 메시지가 없을 경우 서버에서 불 필요한 자원을 낭비하는 단점이 있다.

롤 폴링

폴링의 단점을 보완한 방식으로 클라이언트는 새 메시지가 반환되거나 타임아웃 될 때까지 연결을 유지한다.

1, 메시지를 보내는 클라이언트와 수신하는 클라이언트가 같은 채팅 서버에 접속하게 되지 않을 수 있음 (HTTP는 stateless 상태, 로드밸런싱을 위해 라운드 로빈이 사용될 수 있음)
2, 서버 입장에서 클라이언트가 연결의 해제 여부를 효율적으로 알 수 없음

웹 소켓

웹소켓은 서버가 클라이언트에게 비동기 메세지를 보낼 때 가장 널리 사용하는 기술

한번 맺어진 연결은 영구적이며 양뱡향이다. HTTP 연결이지만 특정 핸드셰이크 절차를 거쳐 웹소켓 연결로 바뀌며 클라이언트에게 비동기적으로 메세지를 전송할 수 있다. 또한 웹소켓을 이용하면 메시지를 보낼 때나 받을 때 동일한 프로토콜을 사용할 수 있다.

무상태(stateless)

HTTP의 특성으로 로그인, 회원가입 등 전통적인 요청/응답 서비스이다.

상태유지(stateful)

상태를 유지해야하는 서비스는 대표적으로 채팅을 들 수 있다. 각 클라이언트가 채팅 서버와 독립적인 네트워크 연결을 유지해야 하기 때문이다.

대규모 트래픽을 처리하기 위한 채팅 아키텍처 설계안

  • 채팅 서버는 클라이언트 사이에 메시지 중재 역할
  • 접속 상태는 사용자의 접속 여부 확인

채팅을 어디에 저장할 것인가?

  • RDB : 사용자의 프로필, 설정, 친구 목록 같은 데이터, 채팅 이력

하지만 채팅 이력은 보통 오래된 채팅을 잘 확인하지 않는다. 그래서 채팅을 저장할 경우는 키-값 저장소를 선택한다.

키-값 저장소를 선택하는 이유

  • 규모 확장이 쉽다.
  • 데이터 접근 지연시간이 짧다.
  • RDB의 경우 데이터가 많아지면 무작위적 접근을 처리하는데 비용이 증가한다.

채팅을 저장하기 위한 키-값 저장소 설계

  • 1:1 채팅

message_id를 키로 설정하여 정렬 해줄 수 있다.

  • 그룹 채팅

channel_id와 message_id를 복합키로 사용한다. channel_id는 파티션 키로도 사용한다.

하지만 NoSQL에서는 auto_increment를 지원하지 않는다. 대안으로는 스노플레이크를 사용하거나 지역적 번호 생성기를 사용하면 된다.

서비스 탐색

채팅 시스템에서 서비스 탐색은 중요하다. 이유는 클라이언트에게 가장 적합한 채팅 서버를 추천해줘야하기 때문이다. 기준으로는 사용자의 위치, 서버 용량 등이 있다. 아파치 주키퍼를 이용하여 구현할 수 있는데 사용 가능한 서버를 모두 등록하고 사용자가 접속을 시도하면 사전에 정한 기준을 최적의 서버를 추천해주는 것이다.

채팅 메시지 아키텍처 흐름

  • 1:1 메시지의 처리 흐름

사용자 A가 채팅 서버1로 채팅 메시지를 보내면 ID생성기를 통해 고유 id를 만들어주고 메시지 큐를 이용하여 키-값 저장소에 저장해준다. 메시지를 받는 사용자는 접속 중이 아니라면 알림을 통해 메시지르의 상태를 전송 받는다.

  • 소규모 그룹 채팅의 메시지 처리 흐름

소규모의 채팅의 경우 사용자A가 채팅을 치면 메시지 큐를 이용하여 각자의 메시지 큐를 확인하여 채팅이 왔는지 안왔는지 확인하면 된다.
이런 방식은 소규모 채팅에서만 유용한데 새로운 메시지가 왔는지 자기의 메시지 큐만 보면 되니 편리하고 그룹이 크지 않기 때문에 메시지를 수신자별로 복사해서 큐에 저장하기 쉽다.

접속 상태 표시

접속상태 표시는 프로필 옆에 온라인이라면 녹색으로 표시되는 것을 말한다. 접속 상태 서버는 웹 소켓을 통해 관리되는 점이 중요하다.

사용자가 로그인을 통해 실시간 서비스인 웹소켓에 연결된다면 접속상태 서버는 사용자에 대한 상태와 타임 스탬프 값을 키-값 저장소에 보관하여 로그인 상태를 표시해준다.
만약 키-값 저장소에 online으로 저장되었던 것이 offline으로 수정된다면 오프라인 상태로 바뀌게 된다.

  • 상태 정보의 전송

상태 정보 서버는 발행-구독 모델로 되어있다.

사용자A의 상태 정보를 친구들이 받고 싶다면 다른 사용자들은 각자 사용자A에 대한 구독 정보를 가지고 있으면 된다. 이런식으로 구현하면 쉽게 친구들은 사용자에 대한 상태 정보를 받을 수 있다. 또한 이 서버는 웹 소켓을 통해 실시간으로 정보를 반영할 수 잇다.
하지만 단점으로는 사용자의 친구가 많아지거나 그룹의 멤버가 많아진다면 상태 변화 한건당 많은 이벤트 메시지가 발행되기 때문에 효율적이지는 않다. (이럴 경우 수동으로 접속 상태를 관리하는게 좋다.)

profile
Java BackEnd Developer

0개의 댓글