DAU 5천만, 일일 메시지 30억 건을 처리하는 채팅 시스템 아키텍처
LINE과 KakaoTalk 사례를 참고하여 고트래픽 상황에서도 안정적으로 동작하는 오픈 채팅방 시스템을 설계합니다.
두 가지 극단적 상황 중 메시지 동시 전송 시나리오를 중점으로 설계했습니다.
핫챗 시나리오 (중점)
동시 입장 시나리오 (추후 통합 예정)
DAU: 50,000,000명
1인당 일일 메시지: 60-100건
일일 총 메시지: 30억 건 (보수적 추정)
평균 TPS: 57,000 msg/sec
피크 TPS: 5,700,000 msg/sec (평균의 100배)
DAU: 5,000만 명
동시 접속률: 40% 가정
실제 동시 접속: 2,000만 명
서버당 수용 가능 연결: 50,000개 (업계 표준: 3-5만)
필요 서버: 2,000만 / 5만 = 400대
최악 시나리오 (100% 동시 접속): 1,000대
방 1개 (5,000명, 초당 5,000 메시지):
메시지 발생: 5,000 msg/sec
필요한 Push: 5,000 × 5,000 = 25,000,000 Push/sec
서버당 부하 (400대): 62,500 Push/sec/서버
→ 단순 계산으로는 WebSocket 서버가 감당 불가능!
[문제]
메시지 1개 발생
↓
400개 WS 서버가 모두 수신 (Redis Pub/Sub)
↓
각 서버가 자기 클라이언트에게 Push
↓
서버당 62,500 Push/sec 필요
↓
CPU/네트워크 과부하!
채팅방 ID로 샤딩하면 핫챗의 모든 부하가 한 샤드에 집중
Redis Pub/Sub은 휘발성 → 서버 다운 시 메시지 유실
[Client 5,000명]
↓ WebSocket (읽기 + 쓰기)
[Load Balancer (NLB)]
↓
[WebSocket 서버 400대]
├─→ Redis Pub/Sub (실시간 알림)
└─→ Kafka (영속성 보장)
↓
[Worker Server]
↓
[Aurora Master]
↓ 복제
[Aurora Replica 10-15대]
[핫챗 감지]
↓
400개 서버 중 40개만 선택
↓
hash(room_id) % 40
↓
선택된 서버만 Subscribe
나머지 360개는 UNSUBSCRIBE
효과: 서버당 부하 10배 감소
[1초간 메시지 수집]
5,000개 메시지 발생
↓
[1개의 배치 이벤트로 묶기]
"5,000개의 새 메시지"
↓
[클라이언트에 1개 Push]
↓
[클라이언트가 한번에 Fetch]
효과: 25M Push → 5K Push (5,000배 감소)
일반 방 (< 100 msg/sec): 1초 배칭
핫챗 (100-1000 msg/sec): 5초 배칭
극한 핫챗 (> 1000 msg/sec): 10초 배칭
[방별 Rate Limit]
초당 1,000개 메시지까지만 허용
초과분은 거부 또는 큐잉
↓
[Load Shedding]
서버 CPU > 80% 시
새 요청 거부 (503)
기존 처리 중인 것만 완료
LINE 오픈챗 사례에서 영감을 받아, TCP의 신뢰성 있는 전달 방식을 채택했습니다.
메시지마다 Sequence 번호 부여
↓
WebSocket으로 Sampling된 메시지만 Push (10%)
↓
클라이언트가 Gap 감지
↓
HTTP API로 빠진 메시지 Fetch
↓
순서 맞춰 화면 표시
{
"type": "message",
"room_id": 12345,
"sequence": 102,
"last_sequence": 105,
"message": {
"id": "msg-102",
"text": "안녕",
"user": "A",
"timestamp": 1234567890
}
}
1. WebSocket으로 수신한 메시지 저장
received: [100, 101, 102, 105]
last_sequence: 105
2. Gap 감지
빠진 sequence: [103, 104]
3. HTTP Fetch API 호출
GET /messages?sequences=103,104
4. 순서대로 화면 표시
100 → 101 → 102 → 103 → 104 → 105
일반 상황: 100% Push
핫챗 감지: 10% Sampling
↓
Push 부하: 25M → 2.5M (10배 감소)
↓
나머지 90%는 클라이언트 Fetch
[WS Server] 메시지 수신
↓
1. Redis Pub/Sub 발행 (실시간)
2. Kafka 발행 (영속화)
↓
문제:
- 이기종 시스템 간 트랜잭션 불가능
- 1번 성공, 2번 실패 시 메시지 유실
- 완벽한 원자성 보장 어려움
-- 트랜잭션으로 묶기
BEGIN TRANSACTION
INSERT INTO messages (...)
INSERT INTO outbox (...) -- 이벤트 발행 예약
COMMIT
-- 별도 프로세스가 Outbox 폴링하여 발행
결정: Outbox 패턴 보류
[WS Server] 메시지 수신
↓
1. Kafka 발행 (영속화, ACK 대기)
2. Redis Pub/Sub 발행 (실시간)
↓
1번 실패 시: 클라이언트에 에러 반환
1번 성공, 2번 실패 시: Kafka에 있으므로 재처리 가능
트레이드오프:
Kafka → Worker → Aurora Master
Client → HTTP API → Aurora Replica (10-15대)
"캐시는 의미 없다"
핫챗 Fetch 부하:
예상 수만 req/sec
↓
Aurora Replica 15대 분산
↓
Replica당 수천 req/sec
↓
충분히 처리 가능! ✅
이유:
- 핫챗 상황에서는 메시지가 너무 빨라 읽기 불가능
- 시스템 안정성이 더 중요
- 배칭으로 10초 지연되어도 사용자 경험에 큰 영향 없음
WebSocket Push: 빠른 알림 (10% Sampling)
HTTP Fetch: 정확한 메시지 조회 (90%)
장점:
- 서버 부하 90% 감소
- 메시지 유실 없음
- 각 채널의 장점 활용
Rate Limit 초과 시:
❌ WebSocket 연결 끊기
✅ 메시지만 드롭 + Fetch로 보완
이유:
- 연결 재설정 오버헤드
- 사용자 경험 저해
- 악의적 사용자만 영향
일반 방: 1초 (실시간성 유지)
핫챗: 5-10초 (안정성 우선)
"1초 텀만 줘도 2배의 공간 확보"
서버 캐시 (X): 히트율 낮음
클라이언트 캐시 (O):
- 메모리 저장
- IndexedDB 영구 저장
- 중복 Fetch 방지
- 오프라인 대응
핫챗은 0.1% 미만
스로틀링의 중요성
메시지 유실 방지
배칭: 임시 방편
- Push 횟수만 줄임
- 처리해야 할 메시지 수는 동일
Rate Limit: 근본 해결
- 애초에 메시지 수 제한
- 서버 보호
조합이 필요!
Redis Pub/Sub:
✅ 빠름
❌ 휘발성 (유실 가능)
❌ 모든 구독자에게 브로드캐스트 (부하 분산 불가)
해결:
- Kafka 병행 (영속성)
- 선택적 Subscribe (부하 분산)
- Sequence 기반 Fetch (유실 복구)
문제:
- 10,000개 방 × Sampling 10% = 대량 Fetch 발생 가능
- 동시에 여러 방에서 핫챗 발생 시 DB 부하 폭증
검토 중인 방안:
- Request Coalescing: 0.5-3초간 동일 요청 모아서 처리
- 클라이언트 로컬 캐싱 최대화
- Aurora Replica 확장
현재: WebSocket으로 읽기 + 쓰기
제안: POST API로 쓰기, WebSocket은 읽기 전용
장점:
- 역할 분리 명확
- Rate Limit 구현 용이
- 확장성 향상
검토 필요:
- 클라이언트 복잡도 증가
- 두 채널 관리 오버헤드
의문:
- 100개 노드로 분산해도 실시간성 보장 가능한가?
- Sharded Pub/Sub 활용 방안?
추가 검증 필요
QR 2,000명 동시 입장:
- MySQL Auto-increment lock 경합
- Rate Limiting 필요
- 비동기 처리 고려
다음 세션에서 논의 예정
WebSocket 서버: 400대 × $500/월 = $200K
Aurora Master/Replica: $100K/월
Kafka Cluster: $50K/월
Redis Cluster: $50K/월
네트워크 및 기타: $50K/월
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
총: $450K/월 (약 5.4억원/월) (실화?)
대규모 채팅 시스템 설계의 핵심은 완벽한 실시간성보다 안정성과 확장성입니다.
병목은 Subscribe에 있었다
완벽한 원자성은 어렵다
캐싱이 항상 답은 아니다
배칭은 근본 해결이 아니다
실시간성 vs 안정성
작성일: 2026년 3월 5일
시스템 디자인 세션 #3 - 오픈채팅 시스템
좋은정보 감사합니다. 이해할때까지 노력해보겠습니다/