pile·
백엔드·엔라이즈엔라이즈·

RabbitMQ 를 이용한 서버-클라이언트 양방향 통신 구현

엔라이즈가 앱과 서버 사이의 양방향 통신을 RabbitMQ로 구현한 기록이다. WebSocket과 Redis Pub/Sub을 검토했다가 접은 이유를 먼저 밝히고, 이미 Celery 브로커로 운용하던 RabbitMQ를 통신 수단으로 확장한 판단을 설명한다. 안드로이드와 파이썬 양쪽의 최소 코드와 실제 활용처 네 가지가 함께 나온다.

핵심 포인트
  • 푸시 메시지는 사용자가 허용하지 않으면 무용지물이고, 폴링은 주기만큼 응답성이 떨어지고 트래픽을 낭비한다.
  • WebSocket은 Node.js 기반이 주류라 파이썬으로 짠 비즈니스 로직이 흩어질 우려가 있었다.
  • Node.js와 파이썬 모두 단일 프로세스 기반이라 장애 시 페일오버와 오토스케일링 관리가 부담이었다.
  • Redis Pub/Sub은 단일 프로세스 이슈가 남고 싱글 스레드라 대규모 처리를 보장하기 어려웠다.
  • RabbitMQ는 메시지 큐라 연결이 끊겨도 재연결 시 큐의 메시지를 순서대로 받을 수 있다.
  • 클라이언트는 큐를 구독하고 서버는 그 큐로 발행하기만 하면 돼 설계 복잡도가 크게 늘지 않는다.
상세 정리
  • 필요 시점: 2016년부터 양방향 통신이 요구됐고 두 서비스 모두 같은 문제를 안고 있었다.
  • 대안의 한계: 푸시는 허용 여부에 좌우되고, 폴링은 중계 서버가 필요 없는 대신 응답성과 트래픽을 희생한다.
  • 기대 효과: 양방향 통신이 있으면 클라이언트의 네트워크 상태에만 의존하면서 자원 낭비를 줄이고, 서버가 언제든 원하는 메시지를 보낼 수 있다.
  • WebSocket을 접은 이유 1: 당시 만족스러운 구현은 Node.js 기반이었는데 단일체 구조를 유지하는 상황에서 로직 분산이 우려됐다.
  • WebSocket을 접은 이유 2: 프로세스 클러스터링은 가능하지만 예기치 못한 종료에 대한 페일오버와 오토스케일링을 안정적으로 관리할 방안을 찾지 못했다.
  • WebSocket을 접은 이유 3: 네트워크 환경에 따라 이벤트가 유실될 위험이 있다.
  • Redis를 접은 이유: Pub/Sub으로 일부는 해결되지만 단일 프로세스 이슈가 남고, 명령 실행 관점에서 싱글 스레드라 대규모 처리 보장이 어려웠다.
  • RabbitMQ의 성격: Erlang으로 작성된 메시지 브로커로 AMQP를 지원하고 다양한 라우팅 모델을 제공하는 오픈소스다.
  • 선택 근거 1: 메시지 큐라 누락 위험이 거의 없고 재연결 시 순서까지 보장된다.
  • 선택 근거 2: Erlang의 특성에서 오는 내결함성과 동시성 성능이 뛰어나 단일 프로세스 서버를 고려할 이유가 사라진다.
  • 선택 근거 3: 내장 저장 구조만으로 구동돼 외부 의존성이 없고, 클러스터로 묶는 수평 확장이 쉽다.
  • 선택 근거 4: 초당 수만 건은 문제없이 전송되며 웹 기반 소켓 프로토콜도 지원해 나중에 웹 앱에도 쓸 수 있다.
  • 선택 근거 5: 여러 언어의 클라이언트 라이브러리를 제공해 iOS와 안드로이드 연동이 가능했다.
  • 구성: 클라이언트는 API 서버와 동기 요청·응답을 주고받는 한편 RabbitMQ와 AMQP 연결을 맺고, 서버가 그 큐로 발행하면 클라이언트가 받아 해석해 동작한다.
  • 클라이언트 구현: 연결 팩토리로 채널을 열고 큐를 선언한 뒤 교환기에 바인딩하고 consume으로 대기한다.
  • 클라이언트 주의점: 앱 생명주기에 맞춰 연결을 켜고 끄고, 중복 연결을 막기 위해 싱글턴으로 설계하기를 권한다.
  • 서버 구현: 파이썬에서 브로커에 연결해 교환기와 라우팅 키를 지정해 발행한다. 서버가 클라이언트별 교환기와 큐 이름을 알고 있어야 한다.
  • 활용 1 채팅: 1대1과 단체 채팅에 쓰며 200명 규모 대화방도 별도 최적화 없이 처리됐다. 목록 화면에서 새 요청과 메시지를 실시간 갱신하는 데도 쓴다.
  • 활용 2 상단 알림: 서버가 보낸 메시지를 즉시 받아 화면 상단에 띄운다.
  • 활용 3 진행 상황: 프로필 조회가 일어날 때마다 진행률이 올라가는 기능처럼 상태를 실시간으로 밀어준다.
  • 활용 4 시그널링: WebRTC 기반 음성 채팅에서 두 피어가 세션 정보와 후보를 교환할 중개자 역할을 이 통신로가 대신한다.
왜 읽나실시간 전달이 필요한데 WebSocket 서버를 새로 세우기가 부담스럽다면, 이미 쓰고 있는 메시지 브로커를 그 용도로 확장하는 선택지와 그 근거를 볼 수 있다.
엔라이즈
엔라이즈 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 백엔드·twilio-engTwilio Engineering·

    Programmable Messaging에서 Verify API로 마이그레이션하기

    Twilio의 Programmable Messaging API로 자체 OTP 솔루션을 운영하던 서비스가 Verify API로 전환하는 방법을 코드 예시와 함께 설명한다. Verify는 OTP 전송·검증을 위한 전용 API로, 전화번호 구매, 토큰 생성, DB 저장·만료 관리를 내부에서 처리해 개발자가 직접 구현할 코드를 크게 줄인다.

    요약 이어보기
    #authentication#twilio#sms+2
  2. 백엔드·포스타입포스타입·

    포스타입이 개인화 추천을 하는 방법 2부

    포스타입 백엔드 엔지니어가 벡터 기반 개인화 추천 시스템을 실제 운영하며 맞닥뜨린 성능 장애와 용량 문제를 해결한 과정을 담은 2부다. 수백만 개의 벡터 KNN 검색이 피크 시간대에 전체 Elasticsearch 검색 성능을 흔드는 문제부터 클러스터 OOM 사태까지, 쿼리 최적화와 인프라 분리 두 가지 경로로 근본 해결에 이른다.

    요약 이어보기
    #elasticsearch#vector-search#recommendation-system+2
  3. 백엔드·포스타입포스타입·

    포스타입이 개인화 추천을 하는 방법 1부

    포스타입이 태그 기반 추천의 한계를 극복하고 벡터 임베딩 기반 개인화 추천 시스템을 구축한 과정을 담은 1부다. 유사한 콘텐츠가 다른 용어를 쓰거나 동일한 태그가 전혀 다른 톤의 콘텐츠를 가리키는 문제를 임베딩 벡터로 해결하고, OpenSearch의 HNSW ANN 검색으로 수백만 벡터를 실시간 검색하는 시스템을 구축해 구매율 15% 향상을 달성했다.

    요약 이어보기
    #opensearch#vector-search#recommendation-system+2