1 pontos por GN⁺ 2025-06-07 | 1 comentários | Compartilhar no WhatsApp
  • TigerBeetle é um banco de dados OLTP especializado em contabilidade de partidas dobradas, desenvolvido com foco em segurança e alta velocidade de processamento
  • Suporta o protocolo de consenso Viewstamped Replication e o critério de strong serializability, com uma arquitetura otimizada para cargas de alta contenção e alto throughput
  • Conta com um projeto e procedimentos de teste fortemente voltados para tolerância a falhas e resiliência a indisponibilidades, buscando operar sem perda de dados em diversos cenários de falha
  • Os testes do Jepsen encontraram diversos bugs e problemas de desempenho em upgrades, testes, modelo operacional e resiliência do cluster, melhorando a capacidade de resposta a esses problemas
  • Na versão mais recente, há várias melhorias e correções de bugs em desempenho de replicação baseada em Ring, tratamento de erros do cliente e precisão de logs e consultas

Introdução ao TigerBeetle

  • TigerBeetle é um banco de dados de processamento de transações online (OLTP) especializado em contabilidade de partidas dobradas (Double-entry bookkeeping)
  • Garante strong serializability com base no protocolo de consenso Viewstamped Replication (VR) e armazena apenas dados de contas e transferências entre contas
  • É adequado para ambientes com alto volume de transações e forte concorrência, como switches internos de bancos, corretagem, emissão de ingressos e medição de energia
  • Sua arquitetura concentra todas as operações de escrita em um único nó (Core), priorizando scale-up em vez de scale-out
  • Busca maximizar o throughput em um único nó com otimizações amigáveis ao hardware, como processamento em lote, paralelismo de IO e esquema fixo

Resiliência a falhas e tolerância a defeitos

  • O TigerBeetle fornece modelos explícitos e procedimentos de recuperação para falhas de memória, processo, relógio, armazenamento e rede
  • A durabilidade dos dados garante ausência de perda de dados mesmo que apenas uma réplica permaneça viva
    • Se os registros forem corrompidos em todas as réplicas, o sistema para de forma segura
  • Assume diversos tipos de falhas, como problemas de hardware/software do sistema, desvios de relógio, corrupção de disco, latência, perda e duplicação na rede
  • Aplica Viewstamped Replication, técnicas de Protocol-Aware Recovery, checksums em blocos de dados e armazenamento em múltiplas réplicas
  • Usa verificação em tempo de execução (assertion) para minimizar impactos quando ocorrem erros e bugs

Forma de upgrade

  • O binário inclui o código da versão atual e de várias versões anteriores
  • O upgrade pode ser feito simplesmente substituindo o binário
  • Todos os nós do cluster mudam de versão automaticamente em modo rolling, com mínima intervenção do usuário
  • Ao evitar que operações commitadas em uma versão sejam commitadas em duplicidade em outra, favorece a prevenção de inconsistências de estado

Modelo de tempo

  • Usa simultaneamente relógios lógicos baseados em views VR e números de operação e relógios físicos híbridos (physical time)
  • O líder coleta o horário POSIX de todas as réplicas e sincroniza o cluster mutuamente dentro de uma margem de erro
  • Se a sincronização dos relógios falhar por mais de 60 segundos, o serviço é recusado
  • Os timestamps usam a unidade de "nanossegundos desde a época Unix", mas há um desvio de 27 segundos em relação ao tempo POSIX real
  • Em ajustes de leap second ou ajustes negativos de tempo, o relógio interno pode desacelerar

Modelo de dados

  • Suporta apenas dois tipos de dados: conta (account) e transferência (transfer)
    • Cada campo tem tamanho fixo, segue o princípio de imutabilidade e é baseado em unsigned int
  • A conta é definida por id de 128 bits definido pelo usuário, ledger, flags, horário de criação e campos customizados
  • A transferência inclui debit/credit account id, code, amount e campos customizados
  • A transferência pode ser executada imediatamente (etapa única) ou em duas etapas (reserva e liquidação negociada)
    • Transferências pendentes (pending) podem ser canceladas ou expirar
    • Transferências especiais podem ser usadas para fechar ou reabrir contas

Modelo operacional e transações

  • O cliente opera em unidades de uma única requisição (batch) para atualizar ou consultar o estado dos dados
  • Cada evento dentro da requisição é processado sequencialmente como uma transação atômica (atomic)
  • Não há suporte para reexecução, transações de múltiplas requisições ou consultas interativas
  • Fornece strong serializability e forte consistência de sessão
  • Suporta sucesso/falha de cada operação, retorno de códigos de erro e processamento composto por meio de Chain (subtransações)

Projeto dos testes Jepsen

  • Executa testes baseados em propriedades (property-based) e injeção de falhas (fault injection) por meio da biblioteca Jepsen
  • Foram realizados experimentos com clusters de 3 a 6 nós em diversos ambientes, como LXC e EC2
  • Devido às restrições do modelo de dados, é difícil verificar consistência no formato tradicional de listas e conjuntos, então a validação de consistência de estado e tempo usa a ordem total das operações (total order)
  • Detecta erros por meio de abordagens complementares como checagem de consistência baseada em timestamp, validação de modelo e simulação

Validação de modelo e geração de operações

  • A correção do comportamento do TigerBeetle é verificada em detalhe com um modelo de máquina de estados single-thread com mais de 1600 linhas
  • Inclui raciocínio e rollback para diversas condições de erro, como ids duplicados, timestamps descontínuos, restrições de saldo e chains encadeadas
  • Para eficiência da validação, são usadas diversas técnicas, como geração de operações e ids, atualização de estado e composição probabilística de consultas

Injeção de falhas

  • Inclui cenários básicos de falha como crash de processo (SIGKILL), pausa (SIGSTOP), partição de rede e alteração de clock
  • Também realiza injeções detalhadas de falhas de armazenamento, como upgrade de versão, simulação de corrupção de arquivos e corrupção parcial em apenas algumas réplicas
  • Valida a minimização da possibilidade de perda de dados com diversos cenários, incluindo corrupção de disco em zigue-zague (helical)

Principais casos de bugs e melhorias

Problema no tratamento de timeout de requisição (#206)

  • No projeto do TigerBeetle, as requisições do cliente nunca entram em timeout; há retry infinito até receber resposta do cluster
  • Na prática, clientes como Java podem lançar exceções de timeout em operações assíncronas, e a aplicação acaba precisando definir timeouts externos
  • Esse desenho oculta de forma ambígua erros de rede ou erros definitivos, dificultando distinguir falhas claras de erros incertos
  • O Jepsen recomendou adicionar formas de retorno por tipo de falha (definitiva/incerta) e opções de retry

Crash da JVM causado por erro no cliente (#2435)

  • Wrappers com thread/assíncronos usados para contornar timeout provocaram um problema de segfault na JVM
  • O problema ocorreu porque um campo não inicializado corretamente era referenciado no cliente Java; corrigido na versão 0.16.12

Crash do cliente ao expirar a sessão (#2484)

  • Encerramento forçado do cliente causado por sessões excessivas
  • A partir da versão 0.16.13, isso foi alterado para retorno de erro

Explosão de latência em falha de nó único (#2739)

  • Uma fraqueza da replicação baseada em anel fazia com que a latência de resposta de todo o sistema aumentasse drasticamente quando alguns nós falhavam
  • Causa: por padrão, o primário envia mensagens passo a passo ao próximo nó; quando alguns nós falham, a ausência de ack causa espera
  • A partir da 0.16.30, foram introduzidas replicação em sentido reverso e topologia de anel dinâmica, melhorando fortemente a latência em falhas

Bug na Header API do cliente Java (#2495)

  • O uso de um objeto singleton para batch de resposta vazio causava compartilhamento incorreto de header e timestamp
  • Não afetava a exatidão dos dados, mas contaminava os resultados da Header API; corrigido na 0.16.14

Omissão de resultados de consulta (#2544)

  • Foi reportado um bug na versão 0.16.13 em que resultados de query_accounts, query_transfers e similares eram parcialmente omitidos, limitando a resposta apenas ao prefixo correto

Conclusão

  • O TigerBeetle é especializado em ambientes dos setores financeiro e contábil que exigem alto nível de segurança e tolerância a falhas
  • A série de testes do Jepsen revelou vários problemas de resiliência, consistência, modelo operacional e desempenho
  • Por meio de colaboração ativa, foram obtidas melhorias concretas em resiliência a falhas, tratamento de erros do cliente, replicação e automação de upgrades
  • Nas versões mais recentes, o sistema oferece um alto nível de confiabilidade, com resposta mais robusta a falhas, garantias de conexão e resposta, e consistência operacional

(Parte deste conteúdo foi elaborada com referência a várias fontes abertas, incluindo Github, documentação oficial do TigerBeetle e relatórios de teste do Jepsen)

1 comentários

 
GN⁺ 2025-06-07
Comentários do Hacker News
  • O texto Fuzzer Blind Spots (Meet Jepsen!) também foi citado como referência, com indicação de https://tigerbeetle.com/blog/2025-06-06-fuzzer-blind-spots-meet-jepsen/

  • Compartilha a experiência de sempre confirmar por fim, via relatórios do Jepsen, as alegações sobre confiabilidade e escalabilidade do TigerBeetle; avalia positivamente que este relatório encontrou vários problemas, que eles foram corrigidos rapidamente e que a suíte interna de testes também foi reforçada para evitar a repetição de bugs semelhantes no futuro. Com essa postura, acredita que, em 10 anos, ele possa alcançar no nicho de bancos de dados financeiros especializados o status de padrão implícito do tipo “é só usar Postgres”. Também registra quanto aprendeu com o excelente trabalho do aphyr.

    • O TigerBeetle tem mais de 6.000 assertions; algumas eram rígidas demais e chegaram a causar certos crashes, mas essas assertions cumpriram exatamente o papel pretendido de alerta. Na prática, houve apenas um pequeno bug de correção em uma funcionalidade interna de testes usada para facilitar a auditoria Jepsen no cliente Java, além de um bug de correção sem impacto na durabilidade encontrado pelo Jepsen. Os detalhes estão explicados neste link. O TigerBeetle está sendo projetado e testado para suportar mais falhas do que o Postgres, adota um modelo explícito de falhas de armazenamento, incorpora resultados de pesquisa que não existiam na época do lançamento do Postgres e aplica várias garantias de estabilidade, como Deterministic Simulation Testing e critérios de código seguro da NASA. Em cenários documentados na literatura em que a perda de dados no Postgres é clara, o TigerBeetle consegue detectar e recuperar. Para mais detalhes, recomenda a seção de helical fault injection do Kyle ou a palestra no QCon London em vídeo.
    • Sempre que lê um relatório do Kyle, sente que sua habilidade com sistemas distribuídos sobe um nível.
  • Demonstra alegria ao ver o TigerBeetle validado pelo aphyr e cumprindo o que promete, como um sinal de esperança de que a abordagem correta pode levar ao resultado certo. Pergunta, porém, como consistência e recuperação funcionam na prática entre o TigerBeetle e sistemas externos menos confiáveis, já que em produção muitos dados além de Account ou Transfer costumam ficar em sistemas externos e bancos separados.

    • Joran, do TigerBeetle, explica o padrão de integração: em geral, recomenda-se uma arquitetura separada entre control plane (OLGP geral, como Postgres) e data plane (OLTP, como TigerBeetle). Informações de usuário ficam no OLGP, uma espécie de “arquivo”, enquanto dados transacionais (estoque → carrinho → pagamento etc.) ficam no OLTP, como um “cofre”. É possível vincular até três identificadores de dados de usuário por conta ou transferência e conectar essas entidades do OLGP a eventos. Essa separação traz vantagens de escalabilidade, operação e gestão independentes. Para casos como bancos, em que dinheiro (cofre) e informação (arquivo) devem ser separados, isso é especialmente convincente. Como a frequência de transações e a frequência de mudanças em informações como nome ou e-mail são diferentes, a estrutura faz sentido. Para consistência de dados, recomenda-se que, no caminho de escrita, os dados dependentes sejam gravados no OLGP (e em armazenamentos externos necessários, como S3) e só então, por último, seja feito o commit no TigerBeetle. No caminho de leitura, a orientação é sempre consultar o TigerBeetle como source of record, garantindo confiança por meio de strict serializability. Também foi indicado o documento de arquitetura.
  • Opina que, se a pessoa leu o post sobre blind spots do fuzzer no Jepsen, este relatório do TigerBeetle fica ainda mais interessante. Observa que o caso de segfault via JNI talvez não fosse evitado nem com linguagens memory-safe como Rust, mas avalia que a abordagem Zig/TigerStyle do TigerBeetle oferece uma boa demonstração de segurança de memória.

    • Relata ter visto ao menos um bug que também poderia ser evitado em Rust; na prática, a maior parte já era bloqueada por assertions, e comenta que, sem TigerStyle, a situação poderia ter sido bem mais perigosa.
  • Fez um pequeno “golf clap” pela criatividade do título da seção "Panic! At the Disk 0".

  • Expressa forte impressão com este relatório detalhado certificado pelo Jepsen; mesmo antes do lançamento do v1.0, a expectativa já está alta. Também elogia separadamente os fundadores por compartilharem insights de forma ativa na thread.

    • Sobre a minúcia do Kyle e o cuidado quase artístico do relatório, comenta que também está ansioso por uma nova apresentação na SD25 Amsterdam.
  • Considera interessante — e “obviamente óbvio” — que, em testes de sistemas distribuídos, seja essencial para uma verificação precisa que o próprio sistema reporte a ordem/o tempo em que os eventos ocorreram internamente, permitindo comparação exata com o modelo externo.

    • Explica-se que isso é possível em um ambiente de strict serializability, mas não sob garantias mais fracas de consistência, onde uma linha do tempo global única é impossível. Também chama atenção o padrão meta em que, ao introduzir um problema mais difícil, o sistema acaba ficando mais simples; por exemplo, ao adicionar como base um protocolo de falha/recuperação de disco, a sincronização de estado de réplicas lentas acaba vindo “de graça”.
  • Depois de revisar o relatório do Jepsen, o blog relacionado e o código de integração com o Antithesis, faz uma pergunta com objetivo de entender o escopo e a eficácia dos testes. Diz que sabia que o TigerBeetle já fazia testes abrangentes com Antithesis, então quer entender como os bugs encontrados pelo Jepsen passaram despercebidos ali, qual é a diferença entre testes com Antithesis e com Jepsen, e como isso difere, em termos concretos, do escopo dos testes internos.

    • Em complemento, aphyr explica que, para generative testing de sistemas distribuídos, são necessários três elementos: 1) ambiente de execução do sistema, 2) gerador de carga, 3) auditor. O Antithesis atua principalmente no item 1, fornecendo um ambiente de simulação determinística. O Jepsen injeta falhas em nível de máquina real e sistema operacional. O VOPR do TigerBeetle executa o cluster inteiro dentro de uma única thread, e cada forma de simulação compensa as vantagens e desvantagens das outras. Neste caso de bug, o ponto decisivo estava nos itens 2) e 3): geração de workload e auditor validador. O código Clojure específico do aphyr para o TigerBeetle foi o que causou e detectou esse bug, e depois eles também corrigiram o código equivalente interno. Na prática, o problema mais crítico estava no VOPR mais do que no próprio banco. Como bancos de dados distribuídos sempre podem ter bugs, é fundamental projetar múltiplos geradores e estratégias de teste.
    • O blog do TigerBeetle também detalha essa questão: em resumo, os testes usados no Antithesis não cobriam a combinação de consultas cruzadas com valores out-of-order necessária para disparar esse bug, então ele passou. O lado do Jepsen conseguiu detectar porque acertou essa combinação. Destaca-se também que o gerador de testes do Jepsen tem suas próprias limitações e que é importante desenhar vários tipos de geradores.
    • 90% dos testes internos de simulação de atraso são executados no VOPR (o simulador próprio), rodando 24/7 em 1.000 núcleos de CPU. O Antithesis é usado como uma camada adicional. Para entender por que esse bug no mecanismo de consultas escapou, foi indicado este post.
  • Diz ter interesse no TigerBeetle e estranha que, na documentação de clientes, não haja cliente em C nem em Zig. Pergunta se esses clientes não existem ou ainda estão em desenvolvimento, já que ele próprio é escrito em Zig.

  • Pergunta se o TigerBeetle já está sendo usado por grandes bancos ou corretoras.

    • Joran, do TigerBeetle, responde que atualmente ele será usado, em parceria com a Gates Foundation, na construção do banco central eletrônico do sistema nacional de pagamentos digitais 2.0 de Luanda. No lado enterprise, já há clientes em produção processando mais de 100 milhões de transações por mês, além de um contrato recente com um unicórnio fintech europeu avaliado em US$ 2 bilhões. Nos Estados Unidos, mais contratos estão em andamento. A demanda pelo TigerBeetle vem crescendo globalmente por causa da necessidade de processamento de transações em tempo real, e os fundadores da Clear Street, uma corretora relevante de médio a grande porte em Wall Street, também participaram do investimento. Os links relacionados indicados foram mojaloop.io, o blog do TigerBeetle e a página da empresa.
    • Não seriam ainda grandes bancos ou bolsas, mas a pessoa diz que já está usando em um novo produto dentro de uma grande fintech.
    • Opina que, por a empresa não ostentar isso na homepage, talvez faltem referências de nomes muito famosos; no momento, o maior endorsement pareceria ser mais a recomendação de um youtuber influente.