Case TigerBeetle — Banco de Dados Financeiro de Missão Crítica em Zig

Case TigerBeetle — Banco de Dados Financeiro de Missão Crítica em Zig

O TigerBeetle representa um dos usos mais ambiciosos e críticos do Zig em produção. Trata-se de um banco de dados distribuído projetado especificamente para contabilidade financeira, onde um único bug pode significar perda de dinheiro real. O fato de que uma equipe escolheu Zig para esse nível de criticidade é uma validação extraordinária da linguagem.

O Problema que o TigerBeetle Resolve

Sistemas financeiros modernos enfrentam um paradoxo: precisam de throughput massivo (milhões de transações por segundo) com correção absoluta (nunca perder centavos). Bancos de dados genéricos como PostgreSQL não foram otimizados para esse caso de uso específico:

  • Double-entry bookkeeping: Cada transação deve debitar uma conta e creditar outra atomicamente
  • Saldo nunca negativo: A menos que explicitamente permitido
  • Auditabilidade total: Cada transação deve ser rastreável
  • Alta disponibilidade: Downtime em sistemas financeiros custa milhões por minuto
  • Throughput extremo: Fintechs e marketplaces processam milhões de eventos por dia

Por Que Zig

Joren Spit, CEO do TigerBeetle, documentou extensivamente a decisão de usar Zig:

Correção de Código

Em um banco de dados financeiro, bugs custam dinheiro literal. O Zig oferece:

  • Detecção de integer overflow: Operações aritméticas em valores monetários nunca silenciosamente overflow
  • Segurança de ponteiros: Eliminação de classes inteiras de vulnerabilidades
  • Controle explícito de erros: Todo caminho de erro é tratado ou explicitamente propagado
  • Safety checks em produção: O modo ReleaseSafe mantém verificações com otimização

Performance Determinística

  • Sem GC: Latência previsível para cada transação
  • Alocação explícita: Uso de memória é modelável e testável
  • io_uring: I/O assíncrono de alta performance no Linux
  • Direct I/O: Bypass do cache do OS para controle total de durabilidade

Compilação Cruzada

O TigerBeetle precisa rodar em Linux x86_64, ARM64, macOS e Windows. O Zig compila para todos esses targets de qualquer máquina de desenvolvimento.

Arquitetura Detalhada

Motor de Armazenamento: LSM-Forest

O TigerBeetle implementa uma variação customizada do LSM-Tree chamada LSM-Forest:

Nível 0: Memtable (RAM) — Escritas recentes
    ↓ Flush quando cheio
Nível 1: SSTable (Disco) — Dados semi-recentes
    ↓ Compactação periódica
Nível N: SSTable (Disco) — Dados antigos

Cada nível é otimizado para o padrão de acesso:

  • Memtable: HashMap em memória para escritas O(1)
  • SSTables: Blocos ordenados e indexados no disco
  • Bloom filters: Eliminação rápida de lookups desnecessários
  • Block cache: Cache LRU de blocos de disco em memória

Protocolo de Consenso: Viewstamped Replication

O TigerBeetle implementa VSR (Viewstamped Replication) para tolerância a falhas:

Operação normal:
1. Cliente envia batch de transferências ao líder
2. Líder replica para backups
3. Maioria (quorum) confirma
4. Líder aplica e responde ao cliente

Failover:
1. Backup detecta que líder está offline
2. Protocolo de eleição de novo líder
3. Novo líder sincroniza estado com quorum
4. Operação normal retomada

Batching Inteligente

O TigerBeetle acumula operações em batches para maximizar throughput:

// Conceitual: como batching funciona
const Batch = struct {
    transferencias: [8192]Transfer,
    count: usize = 0,

    pub fn adicionar(self: *Batch, t: Transfer) !void {
        if (self.count >= self.transferencias.len) {
            try self.flush();
        }
        self.transferencias[self.count] = t;
        self.count += 1;
    }

    pub fn flush(self: *Batch) !void {
        // Escrever batch inteiro no WAL com um único fsync
        try self.wal.writeAll(std.mem.sliceAsBytes(
            self.transferencias[0..self.count]
        ));
        try self.wal.sync();

        // Aplicar no memtable
        for (self.transferencias[0..self.count]) |t| {
            try self.memtable.apply(t);
        }

        self.count = 0;
    }
};

Resultados de Performance

Benchmarks Oficiais

OperaçãoThroughputLatência p99
Transfers (batch)~3.4M/s<1ms
Account lookup~5M/s<0.5ms
Transfers (single)~200K/s<2ms
Recovery (1GB)~30sN/A

Comparação com Alternativas

SistemaTransações/sGarantias
TigerBeetle3.400.000ACID, Distributed
PostgreSQL50.000ACID
MySQL40.000ACID
Redis100.000Eventual
CockroachDB20.000ACID, Distributed

Clientes e Adoção

O TigerBeetle é usado por empresas em produção para:

Fintechs

  • Processamento de pagamentos PIX em tempo real
  • Controle de saldo de carteiras digitais
  • Split de pagamentos em marketplaces

Exchanges

  • Registro de ordens de compra/venda
  • Controle de saldo de ativos digitais
  • Liquidação de operações

Sistemas de Fidelidade

  • Gestão de pontos e recompensas
  • Transferência de pontos entre programas
  • Expiração automática de saldo

Investimento e Sustentabilidade

O TigerBeetle recebeu investimento significativo de VCs de Silicon Valley, validando tanto o produto quanto a escolha tecnológica do Zig:

  • Time de engenharia em tempo integral
  • Contribuições ativas para o compilador Zig
  • Documentação extensiva e open source
  • Programa de suporte empresarial

Técnicas de Zig Utilizadas

Comptime para Verificação

// Verificar invariantes em tempo de compilação
comptime {
    // Transfer deve ter exatamente 128 bytes
    if (@sizeOf(Transfer) != 128) {
        @compileError("Transfer struct tem tamanho incorreto");
    }

    // Alinhamento para Direct I/O
    if (@alignOf(Transfer) % 512 != 0) {
        @compileError("Transfer deve ser alinhada a 512 bytes");
    }
}

Testes Determinísticos

O TigerBeetle usa o sistema de testes do Zig para simulação determinística:

test "transferência atômica entre duas contas" {
    var cluster = try TestCluster.init(testing.allocator, .{
        .replicas = 3,
    });
    defer cluster.deinit();

    // Criar contas
    try cluster.createAccount(.{ .id = 1, .ledger = 1 });
    try cluster.createAccount(.{ .id = 2, .ledger = 1 });

    // Transferir
    try cluster.createTransfer(.{
        .id = 1,
        .debit_account_id = 1,
        .credit_account_id = 2,
        .amount = 1000,
        .ledger = 1,
    });

    // Verificar saldos
    const conta1 = try cluster.lookupAccount(1);
    const conta2 = try cluster.lookupAccount(2);

    try testing.expectEqual(@as(u128, 1000), conta1.debits_posted);
    try testing.expectEqual(@as(u128, 1000), conta2.credits_posted);
}

Lições para o Ecossistema

  1. Zig serve para missão crítica: Se pode gerenciar dinheiro real, pode fazer qualquer coisa
  2. Comptime é game-changer: Verificações em compilação eliminam bugs antes da produção
  3. Performance e segurança não são excludentes: ReleaseSafe prova isso
  4. O modelo de alocador é perfeito para databases: Controle fino de memória é essencial
  5. Comunidade de qualidade: Contribuições do TigerBeetle melhoraram o compilador

Próximos Passos

Explore os detalhes técnicos do TigerBeetle no ecossistema, conheça outros cases como Bun e Ghostty, e veja como fintechs usam Zig em outros contextos. Para oportunidades de carreira, visite nossa seção de carreira.

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.