- Operan un clúster de base de datos NoSQL (ScyllaDB) que procesa 2 millones de mensajes por segundo
- Lo que más impacta el rendimiento de la base de datos es la latencia del hardware de disco físico
→ Cuando el volumen de consultas es bajo no importa mucho, pero al superar cierto punto, solo el tiempo de lectura de 1~2 ms hace que se formen colas de espera para leer del disco y terminen ocurriendo timeouts en las propias consultas
- La latencia de disco normalmente se mide en microsegundos, entonces ¿por qué una operación de disco tarda 1~2 ms?
- Discord opera la mayor parte de su hardware en Google Cloud
- Soporta SSD locales basados en NVMe, pero tras probarlos por su cuenta encontraron problemas de confiabilidad, así que no se sentían cómodos usándolos para almacenar datos importantes
- Persistent Disk puede conectarse o desconectarse del servidor en tiempo real, redimensionarse sin downtime, permite crear snapshots en cualquier momento y está diseñado para replicarse por defecto
→ El problema es que no está conectado directamente al servidor, sino a través de la red
- Por más baja que sea la latencia de una conexión de red local, no puede ser menor que PCI/SATA
→ La red está en 1~2 ms, mientras que un disco conectado directamente está en 0.5 ms
- Con los SSD locales, si ocurre un problema de hardware como en un HDD, se pierden los datos de ese disco, y si el problema ocurre en el host mismo ni siquiera es posible hacer snapshots, así que puede darse una pérdida total de datos
→ Por eso Discord no usa Local SSD y usa Persistent Disk
Análisis del problema
- Lo ideal sería tener un dispositivo de almacenamiento que reuniera solo las ventajas de Local SSD y Persistent Disk, pero eso no existe. ¿Y si al menos se pudiera tomar parte de esas ventajas?
- Para Discord, la latencia de escritura no era el problema. Lo que afecta el rendimiento es la "latencia de lectura"
- "Redimensionar discos sin downtime" no es una función indispensable. El tamaño puede predecirse con anticipación
- Los requisitos finales eran:
- Seguir en GCP
- Usar snapshots point-in-time para respaldo de datos
- Dar máxima prioridad a minimizar la latencia de lectura
- No sacrificar la garantía de uptime de la base de datos existente
- Parecía ideal leer desde Local SSD de GCP y escribir en Persistent Disk
→ ¿Se podría crear un super-disco así a nivel de software?
Crear el Super-Disk
- El requisito en esencia era un caché write-through. Usar Local SSD de GCP como caché y PD como capa de almacenamiento
- Como los servidores de base de datos usan Ubuntu, podían aplicar caché a nivel de disco desde el kernel de Linux (módulos como
dm-cache, lvm-cache y bcache)
- Pero al experimentar vieron que, si aparecían sectores defectuosos en el disco de caché, fallaba toda la operación de lectura
- Cuando aparecen sectores defectuosos, debería leerse desde la capa de almacenamiento y sobrescribirse, pero las soluciones de caché de disco que evaluaron no tenían esa capacidad
- Si ocurrían sectores defectuosos, la base de datos terminaba apagándose por problemas de integridad de datos
- Entonces se agregó un requisito adicional: "debe sobrevivir incluso si aparecen sectores defectuosos en el Local SSD"
- Por eso investigaron
md del kernel de Linux
md permite crear RAID por software
- Hacer mirroring entre SSD y PD no resolvía el problema, porque más de la mitad de las lecturas terminarían viniendo desde PD
md tiene una opción llamada write-mostly que no existe en los RAID tradicionales
- Si se marca un disco como
write-mostly, se excluye de las lecturas normales y solo se lee desde él cuando no hay otra opción. Es "útil para dispositivos conectados lentamente"
- Es decir, si se agrupan SSD y PD en RAID1 y se configura PD como
write-mostly, se pueden cumplir los requisitos
- El último problema que quedaba era que los Local SSD de GCP tienen un tamaño fijo de 375 GB
- Para ciertas aplicaciones, Discord necesita más de 1 TB por instancia de base de datos
- Así que decidieron agrupar varios SSD en RAID0
- La forma final quedó así:
- 4 Local SSD agrupados en RAID0 como
md0
md0 y Persistent Disk agrupados en RAID1 para formar md1
Rendimiento de la base de datos
- El resultado fue exactamente el esperado
- Incluso en picos de carga, las operaciones de disco no se acumulan en cola y la latencia de las consultas no cambia
- El rendimiento mejoró, así que aumentó la cantidad de consultas que cada servidor puede procesar
- Quienes hayan usado RAID quizá se pregunten si esto realmente "simplemente funciona", pero en la práctica ocurrieron muchas cosas, y el resto lo explicarán con más detalle por separado
3 comentarios
Antes no estaban satisfechos con el rendimiento de golang, y viendo que hasta programan servidores en rust, parece que el nivel de "geekismo" de la empresa Discord también es impresionante.
Se siente como intentar tapar algo pequeño con una herramienta enorme.
En HN también se comenta si eso no será simplemente un problema de GCP, pero... https://news.ycombinator.com/item?id=32474093
Creo que vale la pena al menos tener en mente que este tipo de intento también es posible.