1 puntos por GN⁺ 2025-06-07 | 1 comentarios | Compartir por WhatsApp
  • La base de datos OLTP de contabilidad por partida doble TigerBeetle destaca por su seguridad y velocidad, y Jepsen validó la línea 0.16.11~0.16.30 en clústeres Debian de 3 a 6 nodos con inyección de fallas
  • Las pruebas combinaron orden explícito por marcas de tiempo con un modelo de máquina de estados monohilo basado en la documentación para verificar tanto Strong Serializability como la semántica de cuentas, transferencias y consultas
  • Los principales bugs de seguridad fueron omisiones en resultados de consultas con múltiples filtros y un error de marca de tiempo en encabezados del cliente Java; a partir de la 0.16.26, se observaron resultados consistentes con la afirmación de Strong Serializability incluso bajo varias combinaciones de fallas
  • En disponibilidad, salieron a la luz reintentos infinitos del cliente, crashes del proceso al hacer eviction de sesiones, aumentos bruscos de latencia ante la falla de un solo nodo, panic del servidor durante bit flips de disco y upgrades, y la ausencia de una ruta de recuperación ante pérdida de disco en un solo nodo
  • TigerBeetle 0.16.43 incorpora la mayoría de los issues reportados, incluyendo mitigación de latencia ante falla de un solo nodo y tigerbeetle recover, y los operadores deben revisar las notas de la versión al actualizar a 0.16.43 y al migrar a 0.16.26 o superior

Diseño de TigerBeetle y alcance de las pruebas

  • TigerBeetle es una base de datos OLTP para contabilidad por partida doble que almacena solo cuentas (accounts) y transferencias (transfers), en lugar de filas, objetos, grafos o blobs arbitrarios
  • Promete consistencia Strong Serializable basada en Viewstamped Replication (VR), y está diseñada para modelos como transacciones financieras, inventario, ticketing y medición de servicios públicos
  • Para cargas de trabajo de alta contención y alto rendimiento, hace pasar todas las escrituras por un solo núcleo del nodo primary de VR, enfocándose en scale-up más que en scale-out
    • Para el rendimiento usa procesamiento por lotes, paralelización de I/O, esquema fijo y estructuras de datos de tamaño fijo alineadas a caché
  • El modelo de fallas aborda explícitamente memoria, procesos, relojes, almacenamiento y red
    • Los procesos pueden detenerse o crashear
    • Los relojes pueden saltar hacia adelante o hacia atrás
    • Los discos pueden sufrir no solo fallas completas, sino también corrupción por escrituras parciales y contaminación de datos
    • La red puede introducir latencia, pérdida, duplicación, entrega errónea y corrupción de mensajes
  • TigerBeetle usa pruebas de simulación determinista, y las pruebas VOPR simulan el clúster completo junto con las interfaces de reloj, disco y red

Modelo de datos y semántica de las solicitudes

  • El modelo de datos está compuesto por dos tipos de registros: accounts y transfers
    • Las cuentas tienen id, ledger, flags, timestamp, code, user_data_32, user_data_64, user_data_128 y otros campos personalizados de 128 bits
    • Las transferencias son registros inmutables que incluyen debit_account_id, credit_account_id, amount, ledger, flags y campos personalizados
  • Las transferencias pueden aplicarse de inmediato en una sola etapa, y también son posibles las transferencias en dos fases, divididas entre pending y post/void
    • Una pending transfer reserva capacidad en las cuentas de débito y crédito
    • Después se puede hacer post o void por un monto igual o menor al pending amount
    • El campo timeout controla la expiración automática
  • Las cuentas son inmutables salvo por el flag closed y los cuatro campos de saldo, y las transferencias son siempre inmutables
    • Para modificar o revertir una transferencia, hay que crear una nueva transferencia compensatoria
  • Cada solicitud representa una operación lógica de un solo tipo y normalmente puede incluir un lote de hasta 8190 eventos
    • create_accounts y create_transfers son solicitudes de escritura
    • lookup_accounts, lookup_transfers, query_accounts, query_transfers, get_account_transfers y get_account_balances son solicitudes de lectura
  • Cada solicitud es una transacción desde la perspectiva de la base de datos, pero algunos eventos dentro de una solicitud confirmada pueden fallar lógicamente y devolver códigos de error
    • Si se necesita atomicidad condicional entre eventos, se usa chain para que todos los eventos dentro de la misma chain tengan éxito o fallen juntos

Método de pruebas de Jepsen

  • La suite de pruebas de Jepsen combina pruebas basadas en propiedades con inyección de fallas usando la biblioteca de pruebas Jepsen
  • El objetivo de prueba abarcó TigerBeetle 0.16.11 a 0.16.30, incluyendo varios builds de desarrollo
    • Los clústeres se componían de 3 a 6 nodos Debian
    • Se ejecutó tanto en contenedores LXC como en VM de EC2
  • El cliente oficial de TigerBeetle es un smart client que se conecta a todos los nodos, lo que puede ocultar errores de concurrencia
    • Jepsen también prueba el comportamiento normal del smart client
    • Al mismo tiempo, también usó un enfoque que restringe cada cliente a un solo nodo
  • El verificador opera en dos etapas
    • Lee las marcas de tiempo de ejecución de las solicitudes exitosas, e infiere las marcas de tiempo de escrituras fallidas o que agotaron el tiempo de espera a partir de los efectos observados después
    • Ejecuta el modelo de máquina de estados de TigerBeetle basado en la documentación en el orden de las marcas de tiempo inferidas para verificar resultados y códigos de error
  • El modelo de máquina de estados está escrito en más de 1,600 líneas de Clojure e incluye mapas e índices de cuentas y transferencias, transient error, estadísticas internas y flujo del reloj
    • Maneja IDs duplicados, marcas de tiempo no monótonas, restricciones de saldo, flags incompatibles y ejecución especulativa con rollback de chain
    • Usa la biblioteca de estructuras de datos persistentes de alto rendimiento Bifurcan

Inyección de fallas y pruebas de corrupción de archivos

  • Jepsen inyecta SIGKILL y SIGSTOP a procesos, varias formas de partición de red, cambios de reloj desde milisegundos hasta cientos de segundos, y cambios rápidos de ida y vuelta del reloj
  • Durante las pruebas también se realizaron upgrades de nodos entre varias versiones
  • Un nuevo nemesis de corrupción de archivos creó diversos fallos de almacenamiento
    • Simuló daños tipo interferencia cósmica mediante bit flips aleatorios
    • Simuló misdirected write reemplazando chunks de archivo por otros chunks
    • Simuló lost write restaurando después snapshots de chunks de archivo
  • Cada nodo de TigerBeetle tiene un único archivo de datos, dividido en zonas con offsets predecibles
    • Se hicieron pruebas que dañan solo zonas específicas, como el encabezado del WAL o copias redundantes de la zona del superblock
    • También se incluyeron pruebas que dañan múltiples zonas o el archivo completo
  • La falla de disco “helical” corrompe los archivos de todos los nodos, pero daña chunks distintos en cada nodo
    • Como el diseño reciente de archivos de réplica de TigerBeetle suele ser idéntico bit a bit, el objetivo es evitar situaciones en las que un solo registro quede irreparablemente dañado en todas las réplicas
    • La cabecera del WAL es una excepción, porque su posición puede variar entre nodos

Problemas de seguridad detectados

  • En la 0.16.13 ocurría con frecuencia un problema en el que las respuestas de query_accounts, query_transfers y get_account_transfers omitían parte o la totalidad de los resultados
    • Los resultados omitidos siempre estaban al final de la respuesta, y la respuesta era un prefijo del resultado correcto
    • No aparecía en consultas con un solo filtro, sino en combinaciones de múltiples filtros como ledger y code
    • La causa fue un bug de verificación de límites en el zig-zag merge join entre varios índices
    • Se rastreó en #2544 y se corrigió en la 0.16.17
  • La API de encabezados del cliente Java añadida en la 0.16.13 para dar soporte a las pruebas de Jepsen devolvía marcas de tiempo de ejecución incorrectas o duplicadas
    • La causa fue el objeto de respuesta singleton mutable Batch.EMPTY del cliente Java
    • Como las respuestas exitosas se representaban como un batch vacío, varias respuestas sobrescribían el header del mismo objeto
    • Se corrigió en #2495 y se reflejó en la 0.16.14
    • No afecta la consistencia real de los datos; solo afecta la marca de tiempo de solicitud en la API de headers del cliente Java
  • Los resultados observados en la 0.16.26 o posterior coinciden con la afirmación de Strong Serializability de TigerBeetle
    • Esa propiedad se mantiene incluso con combinaciones de pausa de procesos, crash, partición de red, error de reloj, corrupción de disco y upgrade

Problemas de clientes y manejo de solicitudes

  • La documentación de TigerBeetle explica que las solicitudes no expiran por timeout y que el cliente sigue reintentando hasta recibir una respuesta
    • Los métodos asíncronos de Java devuelven CompletableFuture y pueden usar APIs de timeout como .get(timeout, timeUnit) o .orTimeout(...)
    • El Task del cliente .NET también ofrece Wait() basado en timeout
  • Los reintentos infinitos pueden ocultar tanto errores definidos como errores indefinidos
    • Por ejemplo, si una conexión TCP falla con ECONNREFUSED, eso es un fallo definido: la solicitud original no puede ejecutarse
    • Pero si el cliente no se lo informa al llamador y solo sigue reintentando internamente, desde la perspectiva del llamador pasa a ser un fallo indefinido, como un timeout o una interrupción
  • Este problema se está discutiendo en #206 y, al momento del informe, seguía sin resolverse
    • Jepsen recomienda representar los errores definidos e indefinidos como ciudadanos de primera clase y devolverlos al llamador
    • Se pueden mantener los reintentos automáticos, pero deberían ser configurables, y se recomienda ofrecer como opciones el tiempo máximo para iniciar la conexión y para esperar la respuesta
  • El cliente Java 0.16.11 tenía un problema en el que toda la JVM hacía segfault al interrumpir el hilo de llamada síncrona para manejar un timeout o al cerrar el cliente después de una llamada asíncrona
    • La causa fue un campo no inicializado en la estructura de datos de la solicitud
    • Si el cliente se cerraba entre la creación y el envío de la solicitud, se desreferenciaba la dirección por defecto de Zig 0xaaa...
    • Se corrigió en #2435 y se incluyó en la 0.16.12
  • Los clientes oficiales hacían crash de todo el proceso cuando el servidor notificaba una expulsión de sesión
    • TigerBeetle limita por defecto las sesiones concurrentes a 64
    • La expulsión también ocurre cuando se usa una versión de cliente más nueva que la del servidor
    • Desde #2484, a partir de la 0.16.13, en caso de expulsión se devuelve un error al llamador en lugar de hacer crash del proceso

Aumento brusco de la latencia ante fallas de un solo nodo

  • Se repitieron casos en los que la latencia del cliente aumentó entre 3 y 5 órdenes de magnitud ante la falla de un solo nodo
    • En un clúster de 5 nodos, al matar un solo nodo la latencia mínima pasó de menos de 1 ms a 10 segundos
    • En una prueba de un clúster de 3 nodos donde se mató un nodo, la latencia, que era de 1 a 50 ms, subió hasta unos 100 segundos por solicitud y se mantuvo durante casi 1000 segundos, hasta reiniciar el nodo
  • La causa está relacionada con la forma en que TigerBeetle propaga prepare
    • En VR tradicional, el primary envía prepare a todos los secondary y recibe directamente sus ack
    • TigerBeetle organiza los nodos en un anillo: el primary envía prepare al siguiente secondary y cada secondary lo reenvía al siguiente nodo
    • Este enfoque reduce el ancho de banda requerido por un nodo, pero si falla uno de los siguientes f réplicas del anillo, el commit puede quedar bloqueado
  • Este problema se rastrea en #2739
  • La 0.16.30 lo mitigó enviando la mitad de los mensajes prepare en la dirección opuesta del anillo
    • Algunos prepare pueden rodear el nodo fallido
    • En las pruebas de Jepsen, las latencias del orden de 100 segundos bajaron a un rango de 1 a 30 segundos
  • La 0.16.43 incluye mejoras adicionales de rendimiento
    • Los nodos replican en ambas direcciones del anillo
    • La topología del anillo cambia dinámicamente, y el clúster ajusta el orden de los nodos según las condiciones de red y las fallas

Corrupción de disco y crash del servidor

  • En la 0.16.20 hubo casos en los que una corrupción de un solo bit en el superblock, el WAL y la zona grid provocaba un crash al arrancar
    • El log mostraba panic: reached unreachable code y terminaba
    • La causa fue un bug en la verificación del padding de sectores
  • El checksum de TigerBeetle cubre los datos del chunk, pero excluye el padding
    • Si un bit 0 del padding cambiaba a 1, el checksum pasaba
    • Después, fallaba una aserción que verificaba que el padding siguiera siendo 0, y el servidor hacía crash
    • La corrupción del padding no compromete la seguridad y puede corregirse volviéndolo a 0 o recuperándolo de otra réplica
  • VOPR no encontró este bug porque antes corrompía sectores completos
    • La corrupción de sectores activaba fallos de checksum y la ruta de reparación, por lo que no se llegaba a la aserción del padding
    • TigerBeetle añadió errores de un solo byte a VOPR en #2681
    • Desde la 0.16.26, los sectores con corrupción de padding se reparan en lugar de provocar un crash
  • Un bit flip en el número de copia del superblock también podía causar el mismo panic
    • Las cuatro copias del superblock tienen cada una un número copy distinto de 2 bytes, y el checksum omite ese número
    • Si un número de copia corrupto se leía del disco a memoria, al escribir fallaba una aserción del rango 0~3
    • En la 0.16.26 se resolvió reiniciando el número de copia

Problemas relacionados con la actualización

  • Al actualizar de 0.16.25 o anterior a 0.16.26 o posterior, se observó repetidamente el crash panic: checkpoint diverged
    • La causa fue un cambio en la estructura CheckpointState de 0.16.26
    • La nueva versión incluía el conjunto de released blocks, pero durante la transferencia de estado compatible con versiones anteriores esta información podía quedar vacía
    • Si luego un nodo reiniciaba con 0.16.26, podía quedar en un estado donde perdía los released blocks que otras réplicas conocían
    • Una assertion detectaba la divergencia y provocaba el crash para evitar que el cliente observara datos inconsistentes
  • Este problema quedó documentado en el changelog mediante #2745
    • TigerBeetle no publicó una versión parchada de 0.16.26
    • Los operadores deben detener al cliente y esperar a que las réplicas se pongan al día antes de actualizar a 0.16.26 o posterior
  • Al realizar varias actualizaciones seguidas de 0.16.16 a 0.16.28 en unos 20 segundos, o cuando un nodo se pausa/crashea durante una actualización, ocurre un release_transition assertion failure
    • El nodo en ejecución abre el nuevo binary con memfd y lo reemplaza con exec(), pero mientras tanto el binary en disco puede ser sustituido por una versión más reciente
    • El código falla al hacer assert de que incluso el version header en disco coincide con la versión actualmente en ejecución
    • #2758 cambió la assertion por una warning en 0.16.29
  • Al actualizar de 0.16.26 a 0.16.27, aparece panic: switch on corrupt value debido a un deprecated message type
    • El switch del nodo nuevo no tenía un case para el tipo de mensaje antiguo y crasheaba
    • #2763 corrigió esto en 0.16.29 al volver a incluir el deprecated message type en el case para ignorarlo

Recuperación ante pérdida de disco en un solo nodo

  • TigerBeetle es resistente a la corrupción de archivos, pero una falla de disco, incendio, error de volumen EBS o un error del operador puede hacer que todos los archivos de datos de un nodo desaparezcan o queden dañados de forma irrecuperable
  • En el momento del informe, la documentación no explicaba cómo reemplazar un nodo fallido, y existía un procedimiento de recuperación no documentado que consistía en ejecutar tigerbeetle format para inicializar archivos de datos vacíos y esperar que repair resolviera el problema
  • Jepsen confirmó que reformatear funciona en la mayoría de los casos, pero puede no ser seguro
    • Si 2 de 3 nodos tienen una operación confirmada op y se reformatea uno de ellos, una mayoría de 2/3 que no observó op puede realizar un view change y la operación podría perderse
    • En una prueba real hubo una ejecución en la que se perdieron 5 transferencias ya acknowledged
    • También hubo casos donde un nodo formateado con un binary más reciente durante una actualización crasheaba al iniciar antes de completar la transición de versión del clúster
  • Este problema se sigue en #2767
  • Más adelante, TigerBeetle 0.16.43 incluyó el comando tigerbeetle recover para recuperar nodos que sufrieron catastrophic data loss

Conclusiones y recomendaciones de Jepsen

  • Se encontraron dos problemas de seguridad
    • Resultados faltantes en consultas con múltiples filtros antes de 0.16.17
    • Timestamps incorrectos y duplicados en la API de depuración del cliente Java para pruebas de Jepsen
  • Hubo un total de 7 problemas de crash
    • 2 del cliente Java: acceso a memoria no inicializada y crash del proceso durante eviction
    • 5 del servidor: 2 panic relacionados con corrupción de disco y 3 panic relacionados con actualizaciones
    • #2745 quedó documentado, y los demás crash se resolvieron para 0.16.29
  • 0.16.43 resuelve todos los problemas del informe salvo uno
    • El punto no resuelto es que las solicitudes del cliente siguen reintentándose por diseño
  • Las recomendaciones para usuarios son claras
    • Actualizar a 0.16.43
    • Revisar las release notes al pasar a 0.16.26 o cualquier versión posterior
    • Simular fallas de un solo nodo en el entorno de pruebas y medir cómo responde la aplicación al aumento de latencia
  • La arquitectura de TigerBeetle parece sólida, y se observó que la integración de VR, flexible quorum y protocol-aware recovery no dañó las invariantes clave de Strong Serializability
  • Aun así, la validación de Jepsen es un enfoque experimental: puede demostrar la existencia de bugs, pero no su ausencia

1 comentarios

 
GN⁺ 2025-06-07
Opiniones en Hacker News
  • Lectura relacionada: Fuzzer Blind Spots (Meet Jepsen!) – https://tigerbeetle.com/blog/2025-06-06-fuzzer-blind-spots-m...

  • Este informe es realmente impresionante. Cada vez que veía las afirmaciones de confiabilidad y escalabilidad de TigerBeetle, pensaba: “bien, esperemos el informe de Jepsen”
    El informe encontró varios problemas y eso podría preocupar, pero es positivo que no se hayan limitado a corregirlos, sino que también ampliaran su conjunto de pruebas internas para detectar errores similares en el futuro. Con este enfoque de ingeniería, en 10 años TigerBeetle podría convertirse, en el nicho de las aplicaciones financieras, en una base de datos tan predeterminada como “simplemente usa Postgres”
    El trabajo de aphyr también fue excelente, y sentí que aprendí mucho leyendo el informe

    • TigerBeetle tiene más de 6,000 assertions, y algunas eran tan estrictas que provocaron crashes, pero esas assertions cumplieron su función: señalaron que había que ajustar el mental model, y de hecho se ajustó
      Aparte de eso, salvo por un pequeño bug de corrección en una funcionalidad interna de pruebas agregada solo al cliente Java para ayudar con la auditoría de Jepsen, Jepsen encontró un único bug de corrección, y no afectaba la durabilidad. El artículo relacionado está aquí: https://tigerbeetle.com/blog/2025-06-06-fuzzer-blind-spots-m...
      Para ser justos, TigerBeetle está diseñado y probado para tolerar más fallas que Postgres. Esto se debe a que tiene un modelo explícito de fallas de almacenamiento y aprovecha investigaciones que no existían cuando Postgres apareció en 1996. El modelo de fallas de TB se valida adicionalmente con pruebas de simulación determinista, y también usa técnicas como asignación estática de memoria siguiendo las Power of Ten Rules de NASA para Safety-Critical Code. En la literatura hay escenarios conocidos en los que Postgres pierde datos, pero TigerBeetle puede detectarlos y recuperarse
      Para ver más, conviene leer la sección de helical fault injection del informe de Kyle. La mayoría de las implementaciones de Raft y Paxos no están diseñadas para tolerarlo, y también hay una charla de QCon London: https://m.youtube.com/watch?v=_jfOk4L7CiY
    • Siempre espero con ganas los textos de Kyle. Cada vez que publica uno nuevo, se siente como si el conocimiento sobre sistemas distribuidos subiera un nivel
  • Me alegra mucho ver que, tras la verificación de aphyr, TigerBeetle está a la altura de sus propias afirmaciones. Es bueno ver que elegir el enfoque correcto produce resultados correctos
    Me da curiosidad cómo se termina usando TigerBeetle en la práctica. Para todo lo que no sean Accounts o Transfers, habrá muchos sistemas externos y otras bases de datos alrededor de una instalación de TigerBeetle; me pregunto cuál es el patrón típico para que esos sistemas menos confiables se coordinen con TigerBeetle y, especialmente, cómo se recuperan cuando aparecen problemas de consistencia entre ambos

    • El patrón típico al integrar TigerBeetle es separar el plano de control del plano de datos. Para propósito general u OLGP se usa Postgres, y para procesamiento transaccional u OLTP se usa TigerBeetle
      La información de usuarios —nombre, dirección, contraseña, etc.— y la información de productos —descripción, precio, etc.— se colocan en OLGP como “archivador”
      Y en Black Friday, todas las transacciones en las que un usuario mueve un producto desde la cuenta de inventario a la cuenta del carrito, y luego a las cuentas de pago y envío, se colocan en OLTP como “bóveda”. TigerBeetle permite almacenar hasta 3 identificadores de datos de usuario por cuenta o transferencia, de modo que se pueden vincular los eventos entre entidades con la base de datos OLGP que describe esas entidades
      Esta arquitectura [1] ofrece una separación de responsabilidades clara, lo que permite escalar y administrar de forma independiente distintas cargas de trabajo. Si fuera un banco, tendría sentido guardar el efectivo —con características distintas de rendimiento, cumplimiento regulatorio y retención— en una bóveda, en vez de guardar todo el efectivo en el archivador que contiene los registros de clientes
      Este patrón tiene sentido porque la frecuencia con que un usuario cambia su nombre o dirección de correo (OLGP) es mucho menor que la frecuencia con que realiza transacciones (OLTP)
      Para preservar la consistencia, en la ruta de escritura se trata a TigerBeetle como el plano de datos OLTP y la “fuente de verdad”. Cuando llega una transacción de “mover al carrito” o “pagar”, primero se escriben en OLGP las dependencias de datos necesarias; si hay datos blob relacionados, también se escriben en algún lugar como S3; y por último se escribe en TigerBeetle para confirmar la transacción. En la ruta de lectura, se consulta primero la fuente de verdad para preservar la serializabilidad estricta
      [1] https://docs.tigerbeetle.com/coding/system-architecture/
  • Después de leer el artículo de TigerBeetle sobre los puntos ciegos de los fuzzers, este informe de Jepsen resulta especialmente interesante
    El segfault del lado de JNI parece algo que Rust u otro lenguaje con seguridad de memoria tampoco habría evitado. El hecho de que casi no haya bugs de seguridad de memoria parece evidencia de que el enfoque de programación en Zig de TigerBeetle —TigerStyle, si no recuerdo mal— cumple bastante bien el papel que se proponía

    • Ver https://news.ycombinator.com/item?id=44201189. Sí hubo un bug que Rust habría salvado. En cambio, una assertion lo salvó, así que el tocino quedó apenas crujiente, no quemado
      Aun así, es cierto. Sin TigerStyle, los nasal demons nos habrían hecho pedazos
  • Me gustó el informe, excelentemente detallado. Que Jepsen lo haya probado y firmado es una garantía enorme para TigerBeetle. Todavía ni siquiera llegó a v1.0, y ya espero con ganas los nuevos hitos que vengan
    Un aplauso especial también para los fundadores que comparten buenas ideas en este hilo

    • Kyle hizo un trabajo increíble, y el nivel de detalle del informe también fue realmente bueno. Mientras lo leía, pensé todo el tiempo “esto parece una obra de arte”; se sentían la artesanía y la precisión
      Pronto también compartirán novedades en la presentación de SD25 en Amsterdam, así que hay expectativa
  • Me gustó, aunque sea un detalle, el título de la sección “Panic! At the Disk 0”

  • Visto en retrospectiva, es obvio pero interesante que el sistema distribuido bajo prueba tenga que reportar el momento y el orden en que realmente ocurrieron las cosas para poder verificarlo con precisión contra el modelo externo del sistema, en vez de usar el tiempo de reloj de pared

    • Esto funciona porque existe serializabilidad estricta. Con garantías de consistencia más débiles, no necesariamente existe una única línea de tiempo global consistente
      Es un metapatrón interesante: cuando haces algo más difícil, el sistema termina simplificándose
      Otro ejemplo: como hay que asumir que los discos pueden fallar e incluir un protocolo de recuperación, la sincronización del estado de las réplicas rezagadas se obtiene prácticamente “gratis”, porque es exactamente el mismo problema que cuando se daña un disco entero
    • Creo que este es el enfoque clásico. Ej.: https://lamport.azurewebsites.net/pubs/time-clocks.pdf
  • Lamentablemente, en el artículo el enlace al paper “Viewstamped Replication” está roto. https://pmg.csail.mit.edu/papers/vr-revisited.pdf rechaza la conexión
    Probablemente debería usar el esquema http, no https, como en http://pmg.csail.mit.edu/papers/vr-revisited.pdf
    Ahora ya tengo algo para leer el viernes por la noche

    • Se corregirá pronto
      El paper de VSR de 2012 es uno de mis favoritos, y “Protocol-Aware Recovery for Consensus-Based Storage” también es realmente potente
      Que disfrutes la lectura
  • Es una pregunta hecha puramente con ganas de aprender, y espero que no se malinterprete. Estoy empezando a aprender sobre sistemas distribuidos y me fascinan las pruebas de simulación determinista
    Después de mirar por encima el informe de Jepsen sobre TigerBeetle, la publicación de blog relacionada y el código de integración de Antithesis en el workflow de GitHub, me dieron ganas de entender mejor el alcance de las pruebas
    La pregunta central es si la integración con Antithesis también podría haber encontrado estos bugs que encontró el conjunto de pruebas de Jepsen
    La pregunta parte de algunas suposiciones, que podrían estar equivocadas. Pensaba que TigerBeetle ya se probaba exhaustivamente con su conjunto de pruebas interno y con el producto de Antithesis, y entendía que el conjunto de pruebas de Antithesis era más potente que Jepsen, así que me sorprendió que Jepsen encontrara problemas que Antithesis no había encontrado
    Me gustaría saber si entendí mal. Por ejemplo, quisiera saber si 1) el conjunto de pruebas de Antithesis no podía detectar esta clase específica de bugs, 2) esta parte del sistema todavía no estaba cubierta por pruebas de Antithesis, o 3) estoy comparando peras con manzanas porque malinterpreté las distintas fortalezas y objetivos de los conjuntos de pruebas de Jepsen y Antithesis

    • La publicación del blog de TigerBeetle lo explica con más detalle, pero en resumen: aunque las pruebas que corrían en Antithesis eran bastante exhaustivas, no lograron producir la combinación exacta de consultas superpuestas y valores fuera de orden, mientras que el generador de Jepsen sí dio con esa combinación
      Casi con seguridad el generador de pruebas de Jepsen también tiene puntos ciegos. Por eso ayuda diseñar generadores distintos
    • Las pruebas generativas de sistemas distribuidos normalmente necesitan tres componentes. Primero, se necesita un entorno donde ejecutar el sistema. Lo más simple es levantar un clúster de máquinas reales, pero si quieres mejorar el rendimiento, el control de respuestas de APIs externas, el determinismo y la reproducibilidad, conviene algo más sofisticado. Segundo, se necesita un generador de carga que haga que el sistema dentro del entorno realice cosas interesantes. Tercero, se necesita un auditor que observe el comportamiento del sistema bajo carga y determine si cumple con la especificación
      Antithesis aborda principalmente el problema 1, proporcionando un entorno de simulación determinista con máquinas virtuales. Jepsen aborda el mismo problema usando máquinas reales e inyectando fallas a nivel del sistema operativo, mientras que el VOPR propio de TigerBeetle fue diseñado junto con la base de datos para poder ejecutar todo el clúster en un solo hilo. Estos tres enfoques son complementarios y cada uno tiene áreas en las que se destaca
      Lo decisivo en este bug fueron las partes 2 y 3: escribir un validador de carga y un auditor capaces de provocar realmente el bug. En este caso, 1.600 líneas de código Clojure específico para TigerBeetle escritas por aphyr provocaron y detectaron el bug, y luego las pruebas equivalentes del lado de TigerBeetle se parchearon para provocarlo también. En realidad, lo que tenía el bug aquí era más VOPR que la base de datos. Que una base de datos tenga bugs es algo esperable, y no se pueden evitar solo con voluntad. Por eso hace falta una estrategia de pruebas capaz de provocar la mayoría de los bugs; los bugs que se escapan señalan defectos en el generador de cargas
    • El 90% de las pruebas de simulación determinista las realiza principalmente VOPR, el simulador determinista que TigerBeetle creó internamente. Corre 24/7 con una escala de 1.000 núcleos de CPU dedicados
      También usamos Antithesis, pero como una segunda capa de pruebas de simulación determinista
      Para ver por qué se escapó el bug del motor de consultas, consulta aquí: https://tigerbeetle.com/blog/2025-06-06-fuzzer-blind-spots-m...
  • Me da curiosidad si algún banco grande o bolsa de valores usa TigerBeetle

    • A nivel nacional, junto con la Gates Foundation, están integrando TigerBeetle en un switch de banco central sin fines de lucro, y este sistema impulsará el National Digital Payments System 2.0 de Rwanda a fines de este año [1]
      A nivel empresarial, TigerBeetle ya se usa en producción con clientes que procesan más de 100 millones de transacciones al mes, recientemente cerró su primer contrato con un unicornio fintech europeo valuado en 2.000 millones de dólares, y en Estados Unidos también están por cerrarse algunos acuerdos. Debido a la tendencia global hacia el procesamiento de transacciones en tiempo real [2], hay bastante interés de empresas que quieren migrar a TigerBeetle para obtener mayor rendimiento.
      Para responder la pregunta: algunos fundadores de Clear Street, una correduría bastante grande de Wall Street, invirtieron en TigerBeetle [3].
      [1] https://mojaloop.io/how-mojaloop-enables-rndps-2-0-ekash/
      [2] https://tigerbeetle.com/blog/2024-07-23-rediscovering-transa...
      [3] https://tigerbeetle.com/company
    • No es un banco ni una bolsa, pero trabajo en una fintech muy grande y estamos usando TigerBeetle en un producto nuevo.
    • Si tuvieran un cliente así, creo que lo estarían presumiendo en la página de inicio. Hasta ahora, el respaldo más grande que aparece en la página viene de un YouTuber. Es cierto que es un YouTuber popular, pero aun así es un YouTuber.