Como Funciona
Esta página percorre o fluxo real de mensagens entre um cliente e o servidor (cluster) para explicar como o Ticketing funciona. A especificação exata, byte a byte, do que trafega na rede está em Protocolo (API) e Protocolo (Cluster).
Estrutura Geral
Os serviços que recebem as requisições dos usuários (por exemplo, os servidores de evento que tratam a abertura de uma venda de ingressos) entram na fila pela mesma chave junto ao cluster do Ticketing, e apenas o servidor cuja vez chegou prossegue com o trabalho, como decrementar o estoque ou atribuir um assento.
Adquirindo e Liberando um Lock
O fluxo básico. Uma chave livre é concedida imediatamente; uma chave ocupada espera sua vez na fila FIFO. Quando o detentor libera, o lock é repassado diretamente para o início da fila, sem nova disputa — o próximo da fila segue em frente imediatamente com um novo token, então nunca há um momento em que o lock fica vazio, e ninguém consegue furar a fila.
leaseé uma rede de segurança. Se um cliente morre ou esquece de liberar, assim que o tempo deleaseexpira o servidor recupera a chave e a repassa ao próximo da fila. Defina-o com folga — maior que o pior caso de tempo que sua seção crítica pode levar. A v1 aceita somente de 1 a 250 segundos; trabalhos mais longos não são suportados e são rejeitados.waité o limite superior de quanto tempo um cliente espera. Se sua vez não chegar dentro desse tempo, o servidor responde comT(timeout) em vez de conceder o lock, então nenhum lock jamais vaza.0significa uma única tentativa imediata sem entrar na fila. Não existe espera infinita.- Se o mesmo cliente tentar readquirir uma chave que já detém, ele entra na fila como qualquer outro — não é um lock reentrante.
Veja a Matriz Requisição × Estado da Chave para as regras completas de comportamento do servidor por estado de chave, e Restrições de Campo para os intervalos de valores dos campos.
Tokens de Fencing
Mesmo um servidor de lock perfeito não consegue controlar o relógio de um cliente. Sozinho, o Ticketing não consegue impedir o caso do detentor obsoleto: um cliente que travou por um tempo devido a pausas de GC ou sobrecarga enquanto detinha o lock, e depois acorda — sem saber que seu lease já expirou — e continua seu trabalho. É por isso que o token em toda resposta de aquisição é um inteiro u64 garantido a crescer a cada concessão. Em bancos financeiros ou persistentes, a comparação e a atualização do high-water de fencing por chave devem ser atômicas com a escrita de negócio real, na mesma transação de DB ou em uma única escrita condicional. Atualizar apenas a linha de fencing primeiro e executar a escrita real depois não é seguro.
A monotonicidade também vale no cluster — o próprio contador de tokens é replicado por consenso, então, mesmo após uma troca de líder, o novo líder sempre continua a partir de um número maior do que antes. Veja Token de Fencing (especificação) para o formato exato do campo.
Cluster — Sem Interrupções via Consenso Raft
No modo cluster, os nós compartilham um único estado de lock via consenso Raft. Somente o líder trata as requisições dos clientes, e toda mudança de estado do lock (aquisição, liberação, expiração) só é finalizada depois que a maioria dos nós a registrou. Conectar-se a um nó que não é líder resulta em uma resposta M (movido) apontando para o líder.
- Se o líder morre, a configuração atual elege um novo líder em cerca de 2,3 a 2,5 segundos. O mesmo acquire lógico só pode continuar dentro do orçamento
waitrestante quando nenhum byte da requisição foi enviado. Um acquire enviado sem resposta confirmada éIndeterminatee nunca é reenviado automaticamente. - Até a expiração do
leasepassa pelo consenso. Um lock só desaparece depois que o líder confirma o comando de expiração, então pequenas diferenças de relógio entre os nós nunca fazem o estado do lock divergir. - Se o cluster perde a maioria (por exemplo, 2 de 3 nós fora do ar), ele para de aceitar escritas em vez de arriscar emitir um lock inválido (segurança em primeiro lugar). Se o estado volátil do processo de 2 de 3 (ou 3 de 5) nós for perdido, esse domínio cluster/fencing não deve ser recuperado nem inicializado automaticamente com a mesma identidade.
Como o que importa é a maioria, apenas 3 ou 5 nós são permitidos. Um número par de nós apenas aumenta o custo sem melhorar a tolerância a falhas, então o servidor recusa iniciar com um número par.
| Nº de nós | Sem interrupções | Falhas simultâneas toleradas | Observações |
|---|---|---|---|
| 1 | ✗ | — | Monotonicidade do token garantida apenas durante a vida do processo; sem suporte para proteger uma DB persistente reiniciável |
| 3 | ✓ | 1 | Configuração padrão sem interrupções. Suficiente para a maioria dos casos |
| 5 | ✓ | 2 | Redundância mantida mesmo com um nó em manutenção |
Veja Protocolo (Cluster) para o enquadramento (framing) e as regras de porta do RPC entre pares, e a substituição sem interrupção por learner com novo NodeId para substituir os nós um de cada vez.
Comportamento do Cliente
Os clientes oficiais compartilham o seguinte comportamento em comum (veja Bibliotecas para as APIs específicas de cada linguagem).
- Mantém uma conexão persistente por endereço em segundo plano. Dado um único endereço, ele mantém duas conexões com esse mesmo nó, de modo que uma queda breve em um dos sockets não interrompe o serviço.
- Escolhe uma conexão priorizando o líder e depois round-robin. Ele lembra o líder para o qual foi redirecionado pela última vez via
Me envia as requisições seguintes diretamente a ele. - As requisições são feitas em pipeline. A próxima requisição pode ser enviada sem esperar por uma resposta — veja as Regras de Correspondência de Resposta para como as respostas são pareadas com as requisições.
- Uma conexão caída continua tentando reconectar com backoff exponencial (0,1 s até um limite de 3,2 s). Uma conexão morta não quebra o objeto broker — ele se recupera sozinho.
- O mesmo acquire lógico só é tentado de novo internamente se nenhum byte da requisição foi enviado. Um
Bcorrelacionado é Busy/não adquirido definitivo e volta imediatamente ao caller, sem retry interno.Mé apenas um leader hint para a próxima conexão; sem owner/key, não justifica reenviar uma requisição pending já enviada. Um acquire enviado sem resposta confirmada é informado comoIndeterminatee não permite entrar na seção crítica. - A liberação explícita e a compensação de token conhecido usam correspondência exata de owner/token/key e uma fila dedicada limitada. As tentativas terminam em um deadline absoluto de 5 segundos desde request/enqueue, não no lease restante. Sem resposta de sucesso, uma liberação explícita não é informada nem presumida bem-sucedida; o lease do servidor é a rede final.
Conexões e Segurança
Toda conexão (de cliente ou entre pares) é estabelecida na ordem TCP → (TLS) → autenticação por desafio-resposta. O cliente faz o hash do nonce enviado pelo servidor junto com seu token para responder, então o token nunca é enviado em texto claro pela rede, e um nonce novo a cada conexão elimina ataques de replay. Veja Handshake de Autenticação para a especificação exata.
Uma Nota sobre Consistência
- A exclusão mútua é garantida por consenso. Como toda concessão passa por um commit da maioria, a mesma chave nunca é concedida a dois detentores ao mesmo tempo, mesmo durante uma partição de rede ou troca de líder.
- Bancos persistentes devem impor fencing. Somente uma condição high-water por chave, executada atomicamente com a escrita protegida na mesma transação/escrita condicional, impede um cliente que acorda após o
leaseexpirar. O lock ordena o trabalho; o fencing de DB bloqueia a última escrita obsoleta.