1 puntos por GN⁺ 2025-06-07 | 1 comentarios | Compartir por WhatsApp
  • TigerBeetle es una base de datos OLTP especializada en contabilidad de doble entrada, desarrollada con el objetivo de ofrecer seguridad y alta velocidad de procesamiento
  • Soporta el protocolo de consenso Viewstamped Replication y el criterio de strong serializability, con una arquitectura optimizada para cargas de alta contención y alto rendimiento
  • Cuenta con un diseño y procedimientos de prueba muy enfocados en la tolerancia a fallos y la resiliencia ante incidentes, buscando operar sin pérdida de datos en distintos escenarios de falla
  • Las pruebas de Jepsen encontraron diversos bugs y problemas de rendimiento en actualizaciones, pruebas, modelo de operaciones y resiliencia del clúster, y se mejoró la capacidad de respuesta frente a ellos
  • En las versiones más recientes se incluyen varias mejoras y correcciones de errores en el rendimiento de replicación basada en anillo, el manejo de errores del cliente y la precisión de logging y consultas

Introducción a TigerBeetle

  • TigerBeetle es una base de datos de procesamiento de transacciones en línea (OLTP) especializada en contabilidad de doble entrada (Double-entry bookkeeping)
  • Garantiza strong serializability sobre el protocolo de consenso Viewstamped Replication (VR), y solo almacena datos de cuentas y transferencias entre cuentas
  • Es adecuada para entornos con gran volumen de transacciones y fuerte contención concurrente, como switches internos bancarios, corretaje, emisión de boletos y medición eléctrica
  • Tiene una arquitectura en la que un solo nodo (Core) controla todas las operaciones de escritura, por lo que se enfoca en escalado vertical (Scale-up) y no en escalado horizontal (Scale-out)
  • Busca maximizar el rendimiento por nodo único mediante optimizaciones amigables con el hardware como procesamiento por lotes, paralelización de IO y esquema fijo

Resiliencia ante fallos y tolerancia a errores

  • TigerBeetle ofrece modelos explícitos y procedimientos de recuperación para fallos de memoria, proceso, reloj, almacenamiento y red
  • La durabilidad de los datos garantiza que no haya pérdida de datos incluso si sobrevive una sola réplica
    • Si los registros se corrompen en todas las réplicas, el sistema se detiene de forma segura
  • Asume diversos tipos de fallas, como problemas de hardware/software, desviaciones del reloj, corrupción de disco y latencia, pérdida o duplicación en la red
  • Aplica Viewstamped Replication, técnicas de Protocol-Aware Recovery, checksums de bloques de datos y almacenamiento en múltiples réplicas
  • Utiliza verificación en tiempo de ejecución (assertion) para minimizar el impacto cuando ocurren errores o bugs

Método de actualización

  • El binario incluye el código de la versión actual y de varias versiones anteriores
  • La actualización puede hacerse simplemente reemplazando el binario
  • Todos los nodos del clúster cambian de versión automáticamente mediante rolling upgrade, con mínima intervención del usuario
  • Evita que operaciones confirmadas en una versión se vuelvan a confirmar de forma duplicada en otra versión, lo que ayuda a prevenir inconsistencias de estado

Modelo de tiempo

  • Usa simultáneamente un reloj lógico basado en vistas y números de operación de VR, y un reloj físico híbrido (physical time)
  • El líder recopila la hora POSIX de todas las réplicas y sincroniza el clúster dentro de un margen de error permitido
  • Si la sincronización del reloj falla por más de 60 segundos, el servicio se rechaza
  • Los timestamps usan la unidad de "nanosegundos desde la época Unix", pero presentan una desviación de 27 segundos respecto al tiempo POSIX real
  • En ajustes por segundos intercalares o correcciones negativas del tiempo, el reloj interno puede volverse más lento

Modelo de datos

  • Solo soporta dos tipos de datos: cuenta (account) y transferencia (transfer)
    • Cada campo tiene tamaño fijo, sigue el principio de inmutabilidad y está diseñado sobre unsigned int
  • Las cuentas se definen con id de 128 bits definido por el usuario, ledger, flags, hora de creación y campos personalizados
  • Las transferencias incluyen debit/credit account id, code, amount y campos personalizados, entre otros
  • Las transferencias soportan ejecución inmediata (una sola etapa) o procesamiento en dos etapas (reserva y ejecución/negociación)
    • Las transferencias reservadas (pending) pueden cancelarse o expirar
    • Transferencias especiales permiten cerrar o reabrir cuentas

Modelo de operaciones y transacciones

  • El cliente opera en unidades de una sola solicitud (batch) para actualizar o consultar el estado de los datos
  • Cada evento dentro de una solicitud se procesa secuencialmente como una transacción atómica (atomic)
  • No soporta reejecución, transacciones de múltiples solicitudes ni consultas interactivas
  • Ofrece consistencia fuerte (Strong Serializability) y consistencia fuerte de sesión
  • Soporta éxito o fallo por operación, códigos de error y procesamiento compuesto mediante la función Chain (subtransacciones)

Diseño de pruebas de Jepsen

  • Se realizaron pruebas basadas en propiedades (property-based) e inyección de fallos (fault injection) mediante la librería Jepsen
  • Se hicieron experimentos sobre clústeres de 3 a 6 nodos en entornos como LXC y EC2
  • Debido a las restricciones del modelo de datos, era difícil verificar consistencia con listas o conjuntos tradicionales, así que se validó la coherencia de estado y tiempo usando orden total de operaciones (total order)
  • Se detectaron errores con métodos complementarios como validación de consistencia basada en timestamps, verificación de modelos y simulación

Verificación del modelo y generación de operaciones

  • Se verificó detalladamente la corrección del comportamiento de TigerBeetle con una máquina de estados de un solo hilo de más de 1600 líneas
  • Se manejaron razonamiento y rollback para diversas condiciones de error, como ids duplicados, timestamps discontinuos, restricciones de saldo y cadenas enlazadas
  • Para mejorar la eficiencia de validación se usaron diversos enfoques, como generación de operaciones e ids, actualización de estado y combinaciones probabilísticas de consultas

Inyección de fallos

  • Incluye escenarios básicos de falla como crash de proceso (SIGKILL), pausa (SIGSTOP), particiones de red y cambios de reloj
  • También incluye inyección detallada de fallos de almacenamiento, como actualizaciones de versión, simulación de corrupción de archivos y corrupción parcial en solo algunas réplicas
  • Se verificó la minimización del riesgo de pérdida de datos con distintos escenarios, incluida la corrupción de disco en zigzag (helical)

Principales bugs y mejoras

Problemas en el manejo de timeout de solicitudes (#206)

  • Según el diseño de TigerBeetle, las solicitudes del cliente nunca hacen timeout; reintentan indefinidamente hasta recibir respuesta del clúster
  • En la práctica, clientes como Java pueden generar excepciones de timeout en operaciones asíncronas, y las aplicaciones terminan necesitando timeouts externos
  • Este diseño oculta de forma ambigua errores de red o fallos definitivos, dificultando distinguir entre fallos claros y errores inciertos
  • Jepsen recomendó agregar opciones de retorno por tipo de fallo (definitivo/incierto) y opciones de reintento

Crash de la JVM provocado por errores del cliente (#2435)

  • El wrapping con hilos/asíncrono para evitar timeouts provocó un problema de segfault en la JVM
  • Ocurrió porque el cliente Java referenciaba campos no inicializados correctamente; se corrigió en 0.16.12

Crash del cliente al expirar la sesión (#2484)

  • Se producía cierre forzado del cliente por exceso de sesiones
  • Desde 0.16.13 se mejoró para devolver un error en lugar de cerrar el cliente

Aumento drástico de latencia ante falla de un solo nodo (#2739)

  • Debido a una debilidad de la replicación basada en anillo, cuando fallaban algunos nodos aumentaba drásticamente el tiempo de respuesta total
  • La causa era que el primario enviaba mensajes paso a paso al siguiente nodo, y si alguno fallaba se esperaba por acks que no llegaban
  • Desde 0.16.30 se introdujeron replicación inversa y topología de anillo dinámica, mejorando de forma importante la latencia ante fallos

Bug en la API Header del cliente Java (#2495)

  • Al usar un objeto singleton para batches de respuesta vacíos, se produjo compartición incorrecta de headers y timestamps
  • No afectaba la exactitud de los datos, pero contaminaba los resultados de la API Header; se corrigió en 0.16.14

Resultados faltantes en consultas (#2544)

  • En la versión 0.16.13 se reportó un bug en query_accounts, query_transfers y otras consultas, donde faltaba parte de los resultados y la respuesta quedaba limitada solo al prefix correcto

Conclusión

  • TigerBeetle está especializado para entornos de finanzas y contabilidad que requieren alta seguridad y tolerancia a fallos
  • La serie de pruebas de Jepsen reveló diversos problemas de resiliencia, consistencia, modelo de operaciones y rendimiento
  • Mediante una colaboración activa se lograron mejoras reales en recuperación ante fallos, manejo de errores del cliente, replicación y automatización de actualizaciones
  • En las versiones recientes ofrece un nivel alto de confiabilidad, con respuesta más robusta ante fallos, mejores garantías de conexión y respuesta, y mayor consistencia operativa

(Parte de este contenido fue elaborada tomando como referencia diversas fuentes abiertas, incluyendo Github, la documentación oficial de TigerBeetle y reportes de pruebas de Jepsen)

1 comentarios

 
GN⁺ 2025-06-07
Opiniones en Hacker News
  • También sirve como referencia el artículo Fuzzer Blind Spots (¡Conoce Jepsen!), con más información en https://tigerbeetle.com/blog/2025-06-06-fuzzer-blind-spots-meet-jepsen/

  • Comparten que siempre terminaban validando con reportes de Jepsen todo lo relacionado con la confiabilidad y escalabilidad de TigerBeetle; valoran que en este informe se hayan encontrado varios problemas, que se corrigieran rápido y que además se reforzara la suite interna de pruebas para evitar bugs similares en el futuro. Con esa actitud, esperan que en 10 años TigerBeetle llegue a ser en bases de datos financieras especializadas el equivalente a un “simplemente usa Postgres” como opción por defecto. También reconocen cuánto aprendieron gracias al excelente trabajo de aphyr.

    • TigerBeetle tiene más de 6,000 assertions; algunas eran demasiado estrictas y provocaron ciertos crashes, pero precisamente cumplieron el papel de alerta que se buscaba. En la práctica, solo apareció un pequeño bug de corrección en una función de pruebas internas usada para facilitar la auditoría Jepsen del cliente Java, y Jepsen encontró además un bug de corrección que no afectaba la durabilidad. Los detalles se explican en este enlace. TigerBeetle está diseñado y probado para tolerar más fallas que Postgres, adopta un modelo explícito de fallas de almacenamiento, incorpora resultados de investigación que no existían cuando se lanzó Postgres, y aplica garantías de estabilidad como Deterministic Simulation Testing y estándares de código seguro de la NASA. De hecho, para escenarios documentados de pérdida de datos en Postgres, TigerBeetle puede detectar y recuperarse. Para más detalle, recomiendan la sección de helical fault injection de Kyle o la charla en QCon London video
    • Cada vez que leen un reporte de Kyle sienten que suben un nivel en sistemas distribuidos
  • Expresan alegría de que TigerBeetle haya sido validado por aphyr y esté cumpliendo lo prometido; lo ven como una señal de que el enfoque correcto puede llevar a buenos resultados. Preguntan cómo se maneja en la práctica la consistencia y la recuperación entre TigerBeetle y sistemas externos menos confiables, dado que en producción muchas veces los datos fuera de Account o Transfer quedan en otros sistemas o en otra base de datos.

    • Zoran de TigerBeetle explica el patrón de integración: normalmente recomiendan separar la arquitectura entre control plane (OLGP general, por ejemplo Postgres) y data plane (OLTP, por ejemplo TigerBeetle). La información de usuario va en el OLGP como “archivador”, mientras que los datos transaccionales (inventario → carrito → pago, etc.) van en el OLTP como “caja fuerte”. Se pueden asociar hasta 3 identificadores de datos de usuario por cuenta o transferencia para enlazar entidades y eventos del OLGP. Esta separación ofrece ventajas para escalar, operar y administrar cada parte de forma independiente; ponen como ejemplo que, en un banco, conviene separar el efectivo (caja fuerte) de la información (archivador). Como la frecuencia de transacciones reales y la de cambios de datos informativos (nombre/email, etc.) son distintas, sostienen que esta estructura tiene sentido. Para mantener consistencia, recomiendan que en la ruta de escritura primero se registren las dependencias en el OLGP (y en almacenamientos externos como S3 si hace falta) y al final se haga el commit en TigerBeetle; en la ruta de lectura, consultar siempre TigerBeetle como source of record, aprovechando la strict serializability para garantizar confianza. Adjuntan la documentación de arquitectura
  • Opinión de que, si ya se leyó el post de Jepsen sobre fuzzer blind spots, este reporte de TigerBeetle resulta todavía más interesante. Dicen que el caso de segfault en JNI quizá no quedaría protegido ni usando un lenguaje memory-safe como Rust, pero que el enfoque Zig/TigerStyle de TigerBeetle ofrece una buena demostración en cuanto a seguridad de memoria.

    • Comentan una experiencia con un bug que también podría haberse evitado con Rust; en la práctica, la mayoría se previno con assertions, y mencionan que sin TigerStyle la situación pudo haber sido más peligrosa
  • Pequeño aplauso de golf por el ingenio del título de la sección "Panic! At the Disk 0"

  • Expresan profunda impresión por este detallado reporte certificado por Jepsen. Aunque todavía no sale la v1.0, ya tienen grandes expectativas, y además elogian que los fundadores compartan activamente insights en el hilo.

    • Sobre la minuciosidad de Kyle y el cuidado casi artístico del reporte, también esperan noticias de una nueva charla en SD25 Amsterdam
  • Les parece interesante que, en pruebas de sistemas distribuidos, para una verificación precisa sea esencial que el propio sistema reporte directamente el orden/tiempo en que ocurren los eventos internos y así se pueda contrastar con exactitud contra un modelo externo; lo sienten como algo “claramente obvio”.

    • Explican que esto es posible en un entorno de strict serializability, pero que bajo garantías de consistencia más débiles no existe una única línea de tiempo global. También les parece interesante el patrón meta donde, al introducir un problema difícil, el sistema termina simplificándose; por ejemplo, si se agrega desde el inicio un protocolo de falla/recuperación de disco, se obtiene “gratis” la sincronización de estado de réplicas lentas
  • Tras revisar el reporte de Jepsen, el blog relacionado y el código de integración con Antithesis, preguntan con fines de aprendizaje sobre el alcance y la efectividad de las pruebas. Entendían que TigerBeetle ya hacía pruebas amplias con Antithesis, así que les intriga por qué el bug hallado por Jepsen no fue detectado ahí; piden una explicación concreta sobre la diferencia entre las pruebas de Antithesis, Jepsen y las internas.

    • Aphyr aclara que para hacer generative testing en sistemas distribuidos se necesitan tres elementos: 1) entorno de ejecución del sistema, 2) generador de carga y 3) auditor. Antithesis se enfoca sobre todo en el punto 1, proporcionando un entorno de simulación determinista; Jepsen, en cambio, inserta fallas a nivel de máquinas reales y sistema operativo; y VOPR de TigerBeetle ejecuta todo el clúster dentro de un solo hilo. Cada enfoque de simulación compensa las ventajas y desventajas de los otros. En este bug en particular, lo decisivo fueron los puntos 2) y 3): la generación de carga y el auditor de verificación. El código Clojure específico de aphyr para TigerBeetle provocó y detectó ese bug, y luego también se parchó el código interno equivalente. De hecho, el problema clave estaba más en VOPR que en la base de datos misma. En una base de datos distribuida siempre puede haber bugs, por lo que diseñar múltiples generadores y estrategias de prueba es fundamental.
    • El blog de TigerBeetle también explica este tema en detalle. En resumen, la prueba usada en Antithesis no cubría la combinación de consultas cruzadas y valores out-of-order necesaria para este bug, mientras que Jepsen sí dio con esa combinación y logró detectarlo. También remarcan que el generador de pruebas de Jepsen tiene límites y que hace falta diseñar diversos generadores.
    • El 90% de las pruebas internas de simulación de latencia se ejecutan en VOPR (su simulador propio), corriendo 24/7 sobre 1,000 núcleos de CPU, y Antithesis se usa como una capa adicional. Sobre por qué se escapó el bug del motor de consultas, remiten a este post
  • Dicen que les interesa TigerBeetle y les parece raro que, según la documentación de clientes, no haya cliente para C o Zig; preguntan si no existe o si está en desarrollo, siendo que está escrito directamente en Zig

  • Preguntan si TigerBeetle ya se usa en grandes bancos o firmas de corretaje.

    • Zoran de TigerBeetle responde que actualmente se usará, en colaboración con la Gates Foundation, para construir el sistema nacional de pagos digitales 2.0 del banco central electrónico en Luanda. A nivel enterprise, ya operan clientes en producción con más de 100 millones de transacciones mensuales, recientemente firmaron con un unicornio fintech europeo valuado en 2 mil millones de dólares, y en Estados Unidos hay más contratos en proceso. Señalan que la demanda por procesamiento de transacciones en tiempo real está impulsando la adopción global de TigerBeetle, y mencionan que entre sus inversionistas están los fundadores de Clear Street, un brokerage mediano-grande relevante en Wall Street. Comparten estos enlaces: mojaloop.io, blog de TigerBeetle, compañía
    • No son grandes bancos ni bolsas, pero comentan que en su gran fintech ya lo usan en un producto nuevo
    • Opinan que, como no lo presumen en su sitio web, probablemente no haya referencias de nombres grandes; por ahora, creen que la mayor endorsement visible es la recomendación de un youtuber influyente