- Operava um cluster de banco de dados NoSQL (ScyllaDB) que processa 2 milhões de mensagens por segundo
- O fator que mais impactava o desempenho do banco era a latência do hardware de disco físico
→ Em níveis baixos de consultas isso não importava, mas ao ultrapassar certo ponto, apenas o tempo de leitura de 1~2 ms já criava fila de espera no disco, causando timeout nas próprias consultas
- A latência de disco normalmente é medida em microssegundos, então por que uma operação de disco levava 1~2 ms?
- O Discord opera a maior parte do hardware no Google Cloud
- Há suporte a SSD local baseado em NVMe, mas em testes próprios foram encontrados problemas de estabilidade, então não era confortável usá-lo como armazenamento de dados críticos
- O Persistent Disk pode ser conectado e desconectado do servidor em tempo real, redimensionado sem downtime, permite criar snapshots a qualquer momento e foi projetado com replicação por padrão
→ O problema é que ele não fica conectado diretamente ao servidor, e sim pela rede
- Por menor que seja a latência de uma conexão de rede local, ela não fica abaixo de PCI/SATA
→ Rede: 1~2 ms, disco conectado diretamente: 0,5 ms
- Com SSD local, se houver um problema de hardware como nos HDDs, os dados daquele disco são perdidos; e se houver problema no próprio host, nem snapshots são possíveis, podendo resultar em perda total dos dados
→ Por isso o Discord não usou Local SSD e passou a usar Persistent Disk
Análise do problema
- O ideal seria ter um dispositivo de armazenamento que reunisse apenas as vantagens do SSD local e do Persistent Disk, mas isso não existe. E se fosse possível aproveitar pelo menos parte das vantagens?
- Para o Discord, a latência de escrita não era o problema. O que afetava o desempenho era a "latência de leitura"
- "Redimensionamento de disco sem downtime" não era um requisito essencial. O tamanho podia ser previsto com antecedência
- Os requisitos finais eram:
- Continuar no GCP
- Usar snapshots point-in-time para backup dos dados
- Priorizar acima de tudo a minimização da latência de leitura
- Não sacrificar a garantia de uptime do banco de dados existente
- Parecia bom usar o Local SSD do GCP para leitura e o Persistent Disk para escrita
→ Seria possível criar esse tipo de superdisco no nível de software?
Criando o Super-Disk
- O requisito, na prática, era um cache write-through. Usar o SSD local do GCP como cache e o PD como camada de armazenamento
- Como os servidores de banco usavam Ubuntu, era possível aplicar cache em nível de disco no kernel Linux (
dm-cache, lvm-cache, bcache etc.)
- Mas, nos testes, quando surgiam bad sectors no disco de cache, toda a operação de leitura falhava
- Quando aparece um bad sector, seria preciso reler da camada de armazenamento e sobrescrever, mas as soluções de cache de disco avaliadas não tinham essa função
- Quando havia bad sectors, o banco de dados acabava sendo desligado por problemas de integridade dos dados
- Então foi adicionado outro requisito: "precisa sobreviver mesmo que haja bad sectors no SSD local"
- Por isso, passaram a analisar o
md do Linux
- O
md permite criar RAID via software
- Espelhar SSD e PD não resolvia o problema, porque mais da metade das leituras acabaria vindo do PD
- O
md tem a opção write-mostly, que não existe no RAID tradicional
- Se um disco específico for definido como
write-mostly, ele é excluído das leituras normais e só é usado para leitura quando não há outra opção. É "útil para dispositivos conectados lentamente"
- Ou seja, ao agrupar SSD e PD em RAID1 e configurar o PD como
write-mostly, dava para atender aos requisitos
- O último problema restante era que o Local SSD do GCP tem tamanho fixo de 375 GB
- Para certas aplicações, o Discord precisava de mais de 1 TB por instância de banco
- Então decidiram agrupar vários SSDs em RAID0
- A configuração final ficou assim:
- 4 Local SSDs agrupados em RAID0 formando o
md0
md0 e o Persistent Disk agrupados em RAID1 formando o md1
Desempenho do banco de dados
- O resultado foi exatamente o esperado
- Mesmo nos picos, as operações de disco não se acumulavam em fila, e a latência das consultas não mudava
- O ganho de desempenho aumentou a quantidade de consultas processadas por servidor
- Quem já usou RAID pode se perguntar se isso "simplesmente funciona", mas na prática aconteceram várias coisas, e o restante será apresentado em detalhes separadamente
3 comentários
Antes, eu já achava impressionante o nível geek da Discord por, insatisfeita com a performance do Golang, chegar ao ponto de escrever até servidores em Rust.
Parece uma daquelas situações em que se tenta resolver um problema pequeno com uma solução exagerada.
No HN, há também quem diga: isso não é simplesmente um problema do GCP?
https://news.ycombinator.com/item?id=32474093
Acho que vale a pena pelo menos saber que esse tipo de tentativa também é possível.