멀티 인스턴스 환경에서 채팅 메시지가 유실되는 문제 해결
멀티 인스턴스 환경에서 채팅 메시지가 유실되는 문제 해결
문제 발견
카카오테크캠퍼스 최종 프로젝트에서 팀 채팅 기능을 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가 어디 있는지 알 수가 없다.
해결책 선택
인스턴스 간에 메시지를 동기화해야 했다. 여러 방법을 검토했다.
| 방법 | 장점 | 단점 |
|---|---|---|
| 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이 병목이 될 수 있다
검증: JMeter 부하 테스트
구현만 해서는 안 되고, 실제 오토스케일링 상황에서 메시지가 유실되지 않는지 검증해야 했다.
ALB + Fargate + ECS 구조에서 JMeter로 동시에 100명이 채팅하는 상황을 시뮬레이션했다.
- 정상 상황: 인스턴스 2개로 고정했을 때, 테스트 시나리오에서 메시지 누락이 관측되지 않음을 확인
- 스케일 아웃: 트래픽 증가 후 인스턴스 3개로 확장했을 때, 신규 인스턴스 합류 뒤에도 메시지 수신이 이어지는지 확인
- 스케일 인: 트래픽 감소로 인스턴스가 줄어든 뒤에도, 남은 인스턴스에서 정상 수신 확인
정리
- 단일 인스턴스에서 잘 되던 기능이, 멀티 인스턴스에서도 그대로 잘 된다는 보장은 없었다
- 분산 환경 이슈는 재현이 어려워서, 스케일 아웃과 스케일 인까지 포함한 시나리오로 확인하는 과정이 필요했다
- 선택 이유와 리스크는 말로만 공유하면 누락되기 쉬워서, ADR로 남겨두는 게 도움이 됐다
프로젝트: 카카오테크캠퍼스 3기 최종 프로젝트(대학생 맞춤형 일정 관리 서비스) 관련 링크
- GitHub(Backend): kakao-tech-campus-3rd-step3/Team12_BE
- GitHub(Frontend): kakao-tech-campus-3rd-step3/Team12_FE
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.

