- O Discord redesenhou toda a arquitetura com base em Kubernetes para superar os limites da infraestrutura de busca baseada em Elasticsearch, melhorando de forma drástica o desempenho e a confiabilidade da indexação de mensagens
- A fila anterior baseada em Redis tinha risco de perda de mensagens, mas foi substituída por PubSub, garantindo entrega estável das mensagens e, ao mesmo tempo, classificando-as por cluster/índice para processamento eficiente
- Foi adotada uma arquitetura de "células (cells)", distribuindo a carga em vários pequenos clusters Elasticsearch, resolvendo problemas de sobrecarga de nós e impossibilidade de atualização
- As mensagens de DM pessoal e as mensagens de servidor (guild) passaram a ser indexadas em células separadas, servindo de base para o novo recurso de busca em todos os DMs
- Comunidades extremamente grandes (BFGs) agora podem escalar além do limite máximo de número de mensagens do Lucene por meio de células dedicadas e índices com múltiplos shards
Limites da infraestrutura anterior
- A fila de mensagens baseada em Redis gerava gargalos quando havia falha em nós do Elasticsearch, com possibilidade de perda de mensagens
- Clusters de grande porte (mais de 200 nós) chegavam a ter taxa de falha de indexação de 40% com a falha de um único nó
- Índices que atingiam o limite
MAX_DOCS do Lucene (2 bilhões de mensagens) causavam paralisação total da indexação
- Por causa do sistema envelhecido, até mesmo aplicar o patch do log4shell só era possível após tirar todo o sistema do ar
Estratégia de solução
Reconstrução com base em Kubernetes
- Uso do Elastic Kubernetes Operator (ECK) para automatizar a operação dos clusters Elasticsearch
- Reinicializações em rolling, upgrades de sistema operacional e de software puderam ser feitos com segurança
Distribuição dos clusters com arquitetura de “células (cells)”
- Em vez de um único cluster grande, foram organizados vários clusters pequenos formando uma célula
- Em cada célula, o número de índices é limitado e o tamanho dos shards é mantido em até 50 GB e 200 milhões de mensagens
- Melhora no desempenho de indexação e consulta, além de reduzir a carga de manutenção do estado do cluster
Fila de mensagens baseada em PubSub
- A mudança de Redis → PubSub permitiu manter a fila sem perda de mensagens
- O uso de PubSub também está sendo ampliado para outras funções, como agendamento de tarefas
Indexação em lote por cluster
- As mensagens recebidas via PubSub são classificadas pelo cluster e índice de destino e processadas em paralelo em tasks separadas
- A estrutura de distribuição de mensagens foi implementada com tasks e channels do tokio em Rust
Melhorias na busca
Busca de DM baseada no usuário
- Antes, os DMs eram indexados por canal, o que tornava ineficiente a busca em todos os DMs
- Agora, as mensagens de DM são duplamente indexadas em índices por usuário, permitindo buscar todos os DMs de uma vez
Suporte a BFG (Big Freaking Guilds)
- Índices com múltiplos shards foram adotados para comunidades gigantes que ultrapassam o limite de quantidade de mensagens do Lucene
- Os BFGs são processados em células Elasticsearch dedicadas com estrutura de múltiplos primary shards
- Após dupla indexação simultânea no índice antigo e no novo, as consultas são migradas gradualmente para o novo destino
Resultados
- Indexação de trilhões de mensagens e o dobro de throughput de indexação em comparação com antes
- Tempo de resposta de consulta: média de 500 ms → 100 ms, e p99 de 1 s → menos de 500 ms
- Mais de 40 clusters e milhares de índices em operação
- Upgrades de cluster e reinicializações em rolling totalmente automatizados, sem interrupção do serviço
4 comentários
Operar esse tipo de trabalho em produção... meu respeito.
A engenharia do Discord é sempre uma referência. Tenho inveja.
Eu estava me perguntando o que era pubsub, e pelo visto era um IaaS oferecido pela GCP.
https://cloud.google.com/pubsub?hl=en
Impressionante. Inclusive virar tudo de cabeça para baixo para resolver o problema.