- 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)」アーキテクチャによるクラスター分散
- 従来の大規模単一クラスターの代わりに、小さなクラスター複数を1つのセルとして構成
- 各セル内ではインデックス数を制限し、シャードサイズを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超のクラスターと数千のインデックスを運用中
- クラスターのアップグレードとローリング再起動が完全自動化され、サービス停止なし
4件のコメント
あの作業を運用しながらやるなんて……尊敬します。
Discordのエンジニアリングは、いつも模範になりますね。うらやましいです。
pubsubって何だろうと思っていたら、GCPが提供するIaaSだったんですね。
https://cloud.google.com/pubsub?hl=en
印象的ですね。問題解決のために全面的に作り直すのも。