5 puntos por GN⁺ 2025-01-17 | 1 comentarios | Compartir por WhatsApp
  • rqlite es una base de datos relacional distribuida, ligera y de código abierto, escrita en Go y desarrollada sobre SQLite y Raft
  • Su desarrollo comenzó en 2014 y prioriza la confiabilidad y la calidad; incluso después de más de 10 años de desarrollo y despliegue, se han reportado menos de 10 casos de pánico en entornos de producción
  • Probar sistemas distribuidos requiere una consideración cuidadosa en múltiples capas, y sigue una filosofía de mantener la calidad dentro de la simplicidad

La pirámide de pruebas: un enfoque efectivo

  • Las pruebas de rqlite siguen la "pirámide de pruebas"
    • Pirámide de pruebas: una estructura basada en pruebas unitarias, con pruebas de integración y una cantidad mínima de pruebas end-to-end (E2E)
  • Ofrece una suite de pruebas eficiente, fácil de depurar y orientada a objetivos

Pruebas unitarias: el núcleo de la calidad

  • Las pruebas unitarias evalúan componentes independientes y ofrecen un equilibrio entre velocidad y precisión
  • Gracias a SQLite y a una arquitectura "shared nothing", la mayor parte de la funcionalidad puede cubrirse con pruebas unitarias
  • Del código total de rqlite (aproximadamente 75,000 líneas), las pruebas unitarias representan alrededor de 27,000 líneas
  • Las pruebas se completan en pocos minutos, lo que permite ejecutarlas con frecuencia durante el desarrollo

Pruebas a nivel de sistema: validación del consenso

  • Las pruebas a nivel de sistema validan la interacción entre el módulo de consenso Raft y SQLite
  • Elementos principales de prueba:
    • Replicación de sentencias SQLite entre nodos
    • Operaciones de lectura en distintos niveles de consistencia
    • Validación de recuperación ante fallas del clúster y elección de líder
  • Unas 7000 líneas de código de prueba cubren de forma integral las interacciones en configuraciones de nodo único y de múltiples nodos

Pruebas end-to-end: una capa mínima

  • Las pruebas end-to-end cumplen el rol de smoke tests para verificar el arranque del sistema, la formación del clúster y el funcionamiento básico
  • Están escritas en Python y validan funciones clave ejecutando un clúster real de rqlite
  • Ejemplo: validación de respaldos hacia AWS S3
  • Con alrededor de 5000 líneas de código de prueba, se adopta un enfoque limitado para minimizar el costo de depuración

Pruebas de rendimiento: llevando los límites al máximo

  • Las pruebas de rendimiento evalúan métricas como:
    • Velocidad máxima de INSERT
    • Procesamiento de consultas concurrentes
    • Comparación de uso de memoria, CPU y disco
  • Incluyen pruebas con bases de datos SQLite de más de 2 GB para analizar la gestión de memoria y los cuellos de botella de escritura en disco
  • Permiten detectar problemas de rendimiento y garantizar la estabilidad mediante optimizaciones

Lecciones aprendidas

  • Empezar a probar desde el inicio
    • Las pruebas unitarias son la forma más efectiva de construir confianza en el sistema
    • No se debe postergar la escritura de pruebas unitarias durante el desarrollo, ya que permiten encontrar bugs más rápido que las pruebas de integración o las pruebas E2E
  • Mantener simple el código de prueba
    • La suite de pruebas no es el lugar para insistir en refactorizaciones complejas ni en el principio DRY (Don't Repeat Yourself)
    • Es importante escribir código fácil de entender y permitir también código boilerplate adicional
  • Verificar las pruebas
    • Al escribir una prueba, se vuelve a ejecutar cambiando temporalmente el resultado esperado por el opuesto
    • Una prueba bien escrita debe fallar en ese caso, lo que ayuda a prevenir errores en el propio código de prueba
  • No ignorar los fallos de prueba
    • Incluso los fallos raros o difíciles de entender aportan información importante sobre el software
    • Los casos difíciles de depurar suelen ser oportunidades para descubrir defectos críticos en el código
  • Maximizar el determinismo
    • Construir mecanismos que permitan ejecutar manualmente los procesos automáticos del sistema
    • Ejemplo: la función de snapshots de Raft normalmente se ejecuta de forma semiautomática, pero está diseñada para poder activarse explícitamente durante las pruebas
  • Ser deliberado
    • Las pruebas de integración de nivel superior o las pruebas E2E solo se agregan cuando su necesidad está claramente demostrada
    • El exceso de pruebas puede ralentizar el desarrollo y la depuración
  • Aplicar e iterar
    • En las pruebas de rendimiento, las llamadas a fsync se identificaron como un cuello de botella importante, y las entradas del log de Raft se comprimen antes de escribirse en disco para optimizar el uso del disco
  • Priorizar la eficiencia
    • Mantener una suite de pruebas que pueda ejecutarse en pocos minutos permite un desarrollo iterativo rápido
    • Esta es una ventaja esencial para mantener y dar vida a un proyecto de código abierto

La calidad primero

  • Se respeta la pirámide de pruebas y cada capa de pruebas está diseñada para tener un propósito claro
  • A medida que aumenta la complejidad de los sistemas distribuidos, mantener la simplicidad en las pruebas se vuelve clave
  • El objetivo es construir una base de datos confiable y fácil de operar

1 comentarios

 
GN⁺ 2025-01-17
Comentarios en Hacker News
  • La primera prueba es la más difícil, pero vale la pena agregarla. Después, las siguientes pruebas se vuelven más fáciles.

    • Las pruebas parametrizadas reducen el código repetitivo y permiten una mayor variedad de pruebas.
    • Son útiles cuando es posible validar a fondo las restricciones.
    • Las pruebas de propiedades ayudan a verificar consistencia e invariantes.
    • Es importante usar pruebas de mutación para confirmar que realmente se está probando algo.
  • Es impresionante el compromiso con el proyecto.

  • La pirámide de pruebas se entiende, pero muchas veces faltan niveles y hay que mejorar eso rápido.

    • Cuando se colabora con varios equipos, llenar la capa de e2e termina siendo una tarea de la que nadie se hace cargo.
    • Cuando se usan mecanismos de autenticación como Auth0, probar se vuelve difícil.
    • Sin pruebas e2e, el sistema puede romperse fácilmente.
    • Las pruebas e2e automatizadas permiten identificar problemas con facilidad y hacer rollback.
  • Parece que hay un error de copiar y pegar en las FAQ.

  • Está esperando el informe de Jepsen.

  • También le gustó en formato de video.

  • Envidia la configuración de pruebas de rendimiento.

  • Ha usado rqlite y siente que transmite bien la simplicidad.

  • Está preguntando qué opinan sobre las pruebas de simulación determinista.

  • Tiene curiosidad por saber si rqlite se usa en entornos reales.

  • rqlite es un proyecto original y genial.