- Discord는 기존 Elasticsearch 기반 검색 인프라의 한계를 극복하고자 전체 구조를 Kubernetes 기반으로 재설계, 메시지 인덱싱 성능과 안정성을 획기적으로 개선
- 기존 Redis 큐는 메시지 유실 위험이 있었으나 PubSub로 대체되며 안정적 메시지 전달 보장, 동시에 메시지를 클러스터/인덱스 단위로 분류하여 효율적으로 처리
-
"셀(cell)" 아키텍처를 도입해 다수의 소형 Elasticsearch 클러스터로 분산, 노드 과부하와 업데이트 불가능 문제 해결
- 개인 DM 메시지와 서버(guild) 메시지를 별도 셀에 인덱싱, 새로 도입된 DM 전체 검색 기능의 기반이 됨
- 초대형 커뮤니티(BFGs)는 전용 셀과 다중 샤드 인덱스를 통해 Lucene의 최대 메시지 수 제한을 넘는 스케일링 가능
기존 인프라의 한계
-
Redis 기반 메시지 큐는 Elasticsearch 노드 장애 시 병목 발생, 메시지 유실 가능성 존재
-
대규모 클러스터(200+ 노드)는 단일 노드 장애로 전체 인덱싱 실패율이 40%에 달함
- Lucene의 MAX_DOCS(20억 메시지) 제한에 도달한 인덱스는 완전한 인덱싱 중단 초래
- 노후된 시스템으로 인해 log4shell 패치조차 전체 시스템 오프라인 후 가능
해결 전략
Kubernetes 기반 재구축
-
Elastic Kubernetes Operator(ECK) 활용으로 Elasticsearch 클러스터 운영 자동화
-
롤링 재시작, OS 및 소프트웨어 업그레이드가 안전하게 가능
“셀(cell)” 아키텍처로 클러스터 분산
- 기존 대형 단일 클러스터 대신 작은 클러스터 여러 개를 하나의 셀로 구성
- 각 셀 내에는 인덱스 수를 제한하고, 샤드 크기를 50GB, 2억 메시지 이내로 유지
-
인덱싱과 쿼리 성능 향상, 클러스터 상태 유지 부담 감소
PubSub 기반 메시지 큐
-
Redis → PubSub 전환으로 메시지 유실 없이 대기열 유지 가능
- 다른 기능(작업 예약 등)에도 PubSub 활용 확대 중
클러스터별 배치 인덱싱
- PubSub로 받은 메시지를 대상 클러스터와 인덱스 기준으로 분류하여 별도 task로 병렬 처리
-
Rust의 tokio task + channel로 메시지 분산 처리 구조 구현
검색 기능 개선
사용자 기반 DM 검색
- 기존에는 DM을 채널 단위로 인덱싱하여 전체 DM 검색이 비효율적
- 이제는 사용자별 인덱스로 DM 메시지를 이중 인덱싱, 모든 DM을 한번에 검색 가능
BFG (Big Freaking Guilds) 대응
-
Lucene의 메시지 수 제한을 넘는 초대형 커뮤니티를 위해 다중 샤드 인덱스 도입
- BFG는 전용 Elasticsearch 셀에서 다중 primary shard 구조로 처리
-
기존 인덱스와 새로운 인덱스에 동시에 이중 인덱싱 후, 점진적으로 쿼리 대상 전환
성과
-
수조 개 메시지 인덱싱, 이전 대비 인덱싱 처리량 2배
-
쿼리 응답속도: 평균 500ms → 100ms, p99는 1s → 500ms 미만
-
40개 이상의 클러스터와 수천 개 인덱스 운영 중
- 클러스터 업그레이드 및 롤링 재시작이 완전 자동화되고 서비스 중단 없음