14P by neo 1일전 | ★ favorite | 댓글 1개
  • 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개 이상의 클러스터와 수천 개 인덱스 운영 중
  • 클러스터 업그레이드 및 롤링 재시작이 완전 자동화되고 서비스 중단 없음

인상깊네요. 문제 해결을 위해 뒤엎는 것도.