Post

WebSocket 채팅 안정화 개선기: Redis Pub/Sub 재설계와 운영 지표 검증

WebSocket 채팅 안정화 개선기: Redis Pub/Sub 재설계와 운영 지표 검증

개요

먼저 저희 서비스는 고객이 업무 요청서를 통해 이루미와 매칭된 뒤, 서비스 내 채팅을 중심으로 업무를 진행, 관리하는 구조입니다.

하지만 운영 과정에서 다음 문의가 반복적으로 발생했습니다.

채팅 VOC 예시 1

채팅 VOC 예시 2

  • 이루미 응답 지연 시 대응 방법 문의 및 환불 요청
  • 결과물 확인 경로 문의
  • 업무 시간 연장 방법 문의

즉, 채팅이 단순 메시지 확인 역할에 머물러 있었고, 실제 업무 관리와 실시간 소통을 안정적으로 지원하지 못하는 한계가 있었습니다.

이 문제를 해결하기 위해 채팅 기능 개선을 시작했습니다. 화면 요구사항에 맞춰 API를 정리하는 동시에, 기존 실시간 메시징 구조(WebSocket + Redis Pub/Sub)의 불안정성도 함께 개선했습니다.

이번 작업의 목표는 “더 빠른 시스템”이 아니라, 트래픽 증가/장애 상황에서도 버티는 안정적인 실시간 채팅 구조를 만드는 것이었습니다.


문제 정의

기존 구조는 기본적인 송수신은 가능했지만, 운영 환경에서 다음 문제가 반복되었습니다.

  1. 단일 Listener 병목
    • Listener가 DB 저장, Push 알림, WebSocket 송신까지 모두 처리
    • 처리 시간이 길어지며 수신 지연 발생
  2. 트래픽 완충(Buffering) 구조 부재
    • Pub/Sub 특성상 지연 시 유실 리스크 증가
  3. 관찰 가능성(Observability) 부족
    • 장애 발생 시 병목 지점을 즉시 파악하기 어려움
    • 대응이 늦어지고 CS 처리 근거 확보도 어려움

Before

WebSocket Redis Pub/Sub 채팅 파이프라인 기존 구조


개선 방향

핵심 전략은 다음 3가지였습니다.

  • Listener를 초경량화해 수신 경로 병목 제거
  • Queue/Worker 분리로 버스트 트래픽 흡수
  • 재처리 경로 + 운영 지표로 장애 복원력 확보

After

WebSocket Redis Pub/Sub 채팅 파이프라인 개선 구조


1) Listener 초경량화

기존 Listener는 수신 이후 비즈니스 로직까지 처리하고 있었습니다. 이를 메시지 파싱 + Queue 적재 역할로 축소했습니다.

  • Listener: 수신 및 Queue 적재만 수행
  • Worker: DB 저장, Push, WebSocket 송신 등 비즈니스 처리 담당

효과:

  • Listener가 즉시 반환되어 수신 지연 완화
  • Pub/Sub 소비 경로의 병목 감소

2) Listener 스레드 확장 + BlockingQueue 도입

단일 Listener로는 피크 트래픽 대응이 어려워 구조를 분리했습니다.

  • Listener 스레드풀: 1 -> 4
  • Listener-Worker 사이 BlockingQueue(3,000) 도입
  • Worker 스레드풀은 비즈니스 처리만 담당

스레드 4개 선정 근거

  • 경량 Listener 기준 스레드당 처리량: 약 30 msg/s
  • 피크 유입량: 약 100 msg/s
  • 필요 스레드 수: 100 / 30 = 3.3
  • 스파이크 여유를 포함해 4개로 결정

Queue 3,000 선정 근거

  • 피크 유입(100 msg/s) 기준
  • 유입량 > 처리량 상태를 약 30초 흡수 목표
  • 100 x 30 = 3,000

효과:

  • 역할 분리로 병목 제거
  • 버스트 구간 안정성 향상

3) 재처리 큐: Redis Stream 도입

BlockingQueue 포화 또는 Worker 실패 시, 메시지를 즉시 폐기하지 않고 Redis Stream 재처리 큐로 이관하도록 했습니다.

보완된 점:

  • Pub/Sub(at-most-once) 단점 완화
  • Consumer Group 기반 재처리(at-least-once) 적용

실시간성 우선 정책

채팅은 늦게 도착한 메시지가 오히려 UX를 해칠 수 있어, 내구성과 실시간성 사이에서 아래 정책을 선택했습니다.

  • 1차 실패: Stream으로 이관 후 재처리
  • 재처리 실패: 장기 DLQ 보관 대신 유실 처리

즉, “모든 메시지 보존”보다 “대화 흐름 보존”을 우선했습니다.


4) 운영 관측성 강화

Micrometer + Grafana로 다음 지표를 구성했습니다.

  • 성공 메시지 수
  • 실패 메시지 수
  • 메시지 처리 시간
  • BlockingQueue 적재량 게이지

운영 중 Queue 적재량 급증 시 이상 징후를 빠르게 감지하고, 장애 원인을 단계별로 추적할 수 있게 됐습니다.


5) API 정리 및 화면 연동 개선

화면 설계 변경에 맞춰 채팅 관련 API를 재정리했습니다.

  • 하나로 뭉쳐 있던 응답/액션 경로를 목적에 맞게 분리
  • 화면 흐름과 API 계약을 맞추면서 프론트와 협업해 명세 정리
  • 소켓 연결 수 집계에서 graceful 처리 여부 차이를 맞춰 정합성 개선

효과:

  • 화면-API 불일치로 인한 오류 감소
  • 운영 지표(세션/연결 수) 신뢰도 향상

검증

부하 테스트(k6)

  • 동시 사용자: 100
  • 초당 메시지: 10
  • 테스트 시간: 5분
  • 메시지 전송 성공률: 99.9%

테스트 기준에서 송수신 안정성이 개선됨을 확인했습니다.

운영 관점 결과

  • 메시지 처리 경로에 대한 관측 가능성 확보
  • 장애 징후(Queue 적재량 급증 등) 조기 탐지 가능
  • 재처리 경로 도입으로 일시 실패에 대한 복원력 향상

비즈니스 기능/사용성 성과

  1. 채팅 기능 접근 빈도 증가
    • 활성 사용자당 조회수: 14.68 -> 20.08 (+36.8%)
    • 채팅 화면 접근 빈도와 반복 확인 행동이 증가
  2. 채팅 내 상호작용 증가
    • 활성 사용자당 이벤트: 23.67 -> 30.68 (+29.6%)
    • 업무 관련 기능 사용과 상호작용이 전반적으로 증가
  3. 체류 및 업무 관리 활동 증가
    • 활성 사용자당 평균 참여 시간: 5분 03초 -> 6분 22초 (+26.1%)
    • 채팅 내 업무 관리/소통 활동 시간이 증가
  4. 소통 관련 문의 개선
    • 소통 요청 문의 비율을 약 7% 수준으로 감소

VOC 기반 검증 (업무 > 작업 태그)

채팅은 고객의 업무 소통과 관리가 진행되는 주요 공간으로, 채팅 화면 내 기능과 연관된 업무 > 작업 태그 VOC를 중심으로 변화를 분석했습니다.

  • 업무 > 작업 문의: -21.4% 감소

채팅 기능과 직접적으로 연관된 업무 문의가 감소했습니다.

  • 업무 시간 연장 문의: -45.8% 감소

이는 채팅 화면 개선 이후 업무 관리 기능의 접근성과 가시성이 개선된 결과로 해석할 수 있습니다.


회고

이번 개선은 팀원들과 함께 데이터를 수집하고, 이를 기반으로 문제를 정의해 결과까지 연결한 경험이었습니다. 개발적으로는 대규모 성능 튜닝보다 안정성 강화에 초점을 맞췄지만, 실제 업무 관련 문의 감소로 비즈니스 성과를 확인할 수 있었습니다. 특히 개발자가 구현에만 머무르지 않고, 지표 설계와 결과 해석까지 주도적으로 이끄는 과정의 중요성을 배웠습니다.

  • 실시간 시스템에서는 Listener의 작은 병목이 전체 장애로 확산될 수 있다.
  • Buffering/역할 분리는 트래픽 급증 구간의 안정성에 직접적인 영향을 준다.
  • “재처리 + 관측성”이 있어야 운영 가능한 실시간 시스템이 된다.

이번 작업은 단순 성능 튜닝이 아니라, 오류가 잦던 채팅 시스템을 운영 가능한 구조로 재정비한 프로젝트였습니다.

This post is licensed under CC BY 4.0 by the author.