포스트

멀티 인스턴스 환경에서 채팅 메시지가 유실되는 문제 해결

멀티 인스턴스 환경에서 채팅 메시지가 유실되는 문제 해결

문제 발견

카카오테크캠퍼스 최종 프로젝트에서 팀 채팅 기능을 WebSocket으로 구현했다. 로컬에서 테스트할 때는 아무 문제가 없었다.

그런데 AWS ECS에 배포하니까 오토스케일링으로 인스턴스가 2개 이상이 되면서 이상한 현상이 생겼다.

  • A 사용자가 보낸 메시지가 B 사용자에게 도착하지 않았다
  • 어떤 메시지는 도착하고 어떤 메시지는 안 오는 식이었다

원인 분석

WebSocket 연결은 특정 인스턴스와 맺어진다.

1
2
Client A → Instance 1에 연결
Client B → Instance 2에 연결

Client A가 메시지를 보내면 Instance 1에서 처리되는데, Client B는 Instance 2에 연결되어 있다. Instance 1 입장에서는 Client B가 어디 있는지 알 수가 없다.

[이미지 필요] 멀티 인스턴스 환경에서 WebSocket 연결 분산 다이어그램 (Client A-Instance 1, Client B-Instance 2, 메시지 유실 표시)


해결책 선택

인스턴스 간에 메시지를 동기화해야 했다. 여러 방법을 검토했다.

방법장점단점
DB 폴링구현이 간단하다실시간성이 떨어지고 DB에 부하가 간다
Kafka메시지 영속성이 있다이 정도 규모에는 오버엔지니어링이다
Redis Pub/Sub실시간이고 간단하다메시지 영속성이 없다

채팅 메시지는 DB에도 별도로 기록하고 있어서 Pub/Sub의 메시지 영속성 문제는 신경 쓰지 않아도 됐다. Redis Pub/Sub를 선택했다.


ADR 작성

이 결정을 팀에 공유하기 위해 ADR(Architecture Decision Record)을 작성했다.

핵심 결정 사항:

  • 각 ECS 인스턴스는 Redis 채널을 구독한다
  • 메시지가 발생하면 채널에 publish한다
  • Redis는 메시지를 실시간으로 모든 구독 인스턴스에 전달한다
  • 세션은 각 인스턴스에서 관리하고, Redis는 오직 Pub/Sub 브로커 역할만 한다

리스크:

  • Redis 장애 시 메시지 전달이 안 된다 → 채팅 기능 전체에 영향이 있다
  • 트래픽이 급증하면 Redis Pub/Sub이 병목이 될 수 있다

[이미지 필요] Redis Pub/Sub 기반 멀티 인스턴스 메시지 동기화 아키텍처 다이어그램 (Client → Instance → Redis Pub/Sub → 모든 Instance → 해당 Client)


검증: JMeter로 부하 테스트

구현만 해서는 안 되고, 실제 오토스케일링 상황에서 메시지가 유실되지 않는지 검증해야 했다.

ALB + Fargate + ECS 구조에서 JMeter로 동시에 100명이 채팅하는 상황을 시뮬레이션했다.

  1. 정상 상황: 인스턴스 2개에서 메시지 정합성 100% 확인
  2. 스케일 아웃: 트래픽 급증 → 인스턴스 3개로 확장 → 신규 인스턴스도 메시지 수신 확인
  3. 스케일 인: 트래픽 감소 → 인스턴스 축소 → 남은 인스턴스에서 정상 동작 확인

배운 점

  • 단일 인스턴스에서 잘 돌아가는 코드가 분산 환경에서도 잘 돌아가리란 보장은 없다
  • “돌아간다”와 “안정적으로 돌아간다”는 다르다 — 부하 상황에서도 검증해야 한다
  • 아키텍처 결정에는 근거가 필요하다 — ADR로 기록해두면 나중에 왜 이렇게 했는지 설명할 수 있다

카카오테크캠퍼스 3기 최종 프로젝트(대학생 맞춤형 일정 관리 서비스)에서 경험한 내용 정리.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.