Atualmente em testes: o código do GitHub será aberto quando concluído.

O que é o Ticketing?

Ticketing é um servidor de lock dedicado, projetado para exatamente uma tarefa — lock distribuído. É um único binário de servidor em Rust, combinado com clientes oficiais por linguagem que implementam todos o mesmo protocolo binário, byte a byte. Apenas duas operações — aquisição (acquire) e liberação (release) —, uma fila FIFO por chave, tokens de fencing e um cluster Raft opcional que você ativa quando precisar. Tudo o que um lock distribuído precisa, e nada mais.

Em que isso difere de locks construídos sobre um armazenamento?

A maioria dos locks distribuídos em produção se apoia em um armazenamento chave-valor — um script Lua ou Redlock sobre o Redis, ou um lock construído sobre sessões e leases do ZooKeeper ou do etcd. O Redis é um ótimo armazenamento, mas é um armazenamento chave-valor reaproveitado para lock distribuído, não um sistema de lock feito sob medida, e isso aparece como sobrecarga estrutural: o custo de parsing de um protocolo de propósito geral e a sobrecarga de estruturas de dados de propósito geral vêm juntos.

O Ticketing foi projetado exclusivamente para lock distribuído desde o primeiro dia, então cada camada é construída em torno de locks.

  • Protocolo — campos binários de largura fixa, nem texto nem um formato de serialização de propósito geral. Os valores são lidos diretamente por deslocamento de bytes, sem parsing, e o pipelining permite enviar a próxima requisição sem esperar pela resposta anterior.
  • Internamente no servidor — todo o estado é uma fila FIFO por chave mais um timer de lease. O caminho da requisição nem sequer aloca no heap.
  • Operação — inicie um binário de servidor (ou container), configure-o com algumas variáveis de ambiente e pronto. Nenhum design de esquema, nenhum armazenamento separado, nenhum conhecimento operacional alheio ao lock é necessário.

Desempenho

  • Processa mais de 1 milhão de operações por segundo usando menos de 10 MB de memória
Uma comparação de velocidade com o Redisson (Redis), o sistema de lock distribuído mais utilizado.
Clientes TicketingRedis (Redisson RLock)
JavaScript
210.2 ms · 190,295 ops/s
210.2 ms
Rust
225.9 ms · 177,069 ops/s
225.9 ms
Go
228.4 ms · 175,131 ops/s
228.4 ms
C#
286.9 ms · 139,421 ops/s
286.9 ms
Kotlin
443.5 ms · 90,192 ops/s
443.5 ms
Java
457.8 ms · 87,374 ops/s
457.8 ms
C/C++
659.7 ms · 60,634 ops/s
659.7 ms
Python
739.4 ms · 54,098 ops/s
739.4 ms
Ruby
1,682.4 ms · 23,776 ops/s
1,682.4 ms
Redisreferência
4,909.1 ms · 8,148 ops/s
4,909.1 ms
O comprimento da barra é o tempo total (ms) da execução — quanto menor, mais rápido.
32 contended keys × 1,250 ops · concurrency 64 · mac mini m4 2024 basic (10 core), single local server, acknowledged release, 1s min-work budget

Por que o Ticketing

🚦 Integridade de ordem — fila FIFO com repasse direto

Quem chegou primeiro é atendido primeiro. Quando o detentor libera o lock, ele é repassado diretamente para o início da fila, sem nova disputa. Sem inanição (starvation) causada por disputa via polling e retentativa, e sem tempestades de retentativas.

🛟 Um cliente morto não deixa o lock travado — lease

Se o processo que detém o lock morre ou sua conexão cai, o servidor recupera automaticamente o lock assim que o tempo de lease definido no momento da aquisição expira, e o repassa ao próximo da fila. Esquecer de liberar não paralisa o sistema inteiro.

🔑 Prevenindo trabalho fora de ordem — tokens de fencing

Há uma falha que um lock sozinho não consegue prevenir: um detentor que acorda tarde — sem saber que seu lease já expirou — e pede para concluir o trabalho mesmo assim. O Ticketing emite um token de fencing monotonicamente crescente a cada aquisição. Desde que o recurso protegido aplique uma única regra — "rejeitar qualquer token menor que o último visto" —, mesmo essa última brecha é fechada. Veja Como Funciona para a explicação completa.

🗳️ Um cluster sem interrupções baseado em Raft

Um único servidor já é suficiente por si só, mas, quando você precisa de zero downtime, forme um cluster de 3 (ou 5) nós. Toda mudança de estado do lock só é finalizada depois que a maioria dos nós concorda via consenso Raft, então o mesmo lock nunca é emitido duas vezes ao mesmo tempo, mesmo que o líder morra ou a rede se particione. Se o líder falhar, um novo é eleito em aproximadamente um segundo e os clientes trocam automaticamente. O serviço continua funcionando mesmo quando os nós caem um de cada vez — por exemplo, durante reinicializações de instâncias em nuvem ou uma manutenção sequencial.

🔒 Autenticação e TLS embutidos

Toda conexão passa por autenticação de token por desafio-resposta imediatamente após conectar, e o token nunca é enviado em texto claro pela rede. Criptografe toda a conexão com TLS sempre que precisar.

🌐 O mesmo protocolo, byte a byte, em todas as principais linguagens

Rust, Java/Kotlin, JavaScript/TypeScript, Python, C#, Go, Ruby, C/C++ — todo cliente oficial implementa o mesmo protocolo binário, com uma API que parece natural ao ecossistema de cada linguagem (assíncrona ou bloqueante). Um lock adquirido em qualquer linguagem entra na fila de forma justa com clientes escritos em qualquer outra. Veja Bibliotecas para instruções de instalação e exemplos.

Apenas duas operações

Fiel a um servidor exclusivo de lock, a superfície também é mínima.

  1. Associe uma chave ao recurso que deseja proteger — por exemplo, order-1234, account-77, daily-batch.
  2. Adquira (acquire) essa chave antes de fazer o trabalho — se outra pessoa a detém, você espera sua vez na fila FIFO.
  3. Libere (release) quando o trabalho terminar — o próximo da fila assume imediatamente, sem nova disputa.

As únicas opções além dessas duas operações são lease (recuperação automática) e waitTimeout (desistir de esperar) — essa é toda a API.

O que ler a seguir