Fatos Principais
- A maioria das bibliotecas de consenso (Raft, Paxos) trata a máquina de estado como uma caixa-preta pura.
- Se um líder falha após o efeito colateral mas antes de comprometê-lo, ocorrem duplicatas.
- Chr2 usa uma Caixa de Saída Replicada: Efeitos colaterais são armazenados como 'pendentes' no estado replicado.
- O Fencing Durável usa um manifesto persistido via atomicidade tmp+fsync+rename para impedir líderes zombies.
- Chr2 é um sistema CP, priorizando segurança sobre disponibilidade.
Resumo Rápido
Bibliotecas de consenso padrão como Raft e Paxos geralmente ignoram o que acontece após uma entrada de log ser comprometida. Elas tratam a máquina de estado como uma caixa-preta, assumindo que a aplicação lida com o resto. Essa suposição falha quando a aplicação deve disparar ações externas, como cobrar um cartão de crédito, disparar um webhook ou enviar um e-mail. Se um líder falha após realizar a ação mas antes que o comprometimento seja finalizado, o sistema frequentemente perde o controle da operação. Quando um novo líder assume, ele pode reexecutar o mesmo comando, levando a efeitos colaterais duplicados.
Para resolver isso, uma nova biblioteca chamada Chr2 foi desenvolvida para tratar efeitos colaterais à prova de falhas como um recurso principal e não como um pensamento posterior. A filosofia central é garantir que os efeitos colaterais não sejam apenas registrados, mas gerenciados através de um ciclo de vida de execução estrito. A biblioteca introduz um mecanismo de Caixa de Saída Replicada (Replicated Outbox). Em vez de executar imediatamente, os efeitos colaterais são armazenados como itens 'pendentes' dentro do estado replicado. A execução é estritamente controlada; apenas o líder ativo tem permissão para executar esses efeitos, e ele deve fazer isso sob um token de fencing específico.
Impedir líderes 'zombies' — líderes antigos que voltam online e tentam agir — é crítico. Chr2 usa Fencing Durável para gerenciar isso. Um arquivo de manifesto persiste o maior número de visão (view number) usando operações atômicas (tmp+fsync+rename). Isso garante que um líder antigo não possa acordar e executar efeitos obsoletos. Para garantir consistência durante a recuperação ou replay, o sistema fornece um Contexto Determinístico. O código da aplicação recebe uma semente determinística de RNG (Gerador de Números Aleatórios) e o tempo do bloco diretamente do log, garantindo que o replay do log produza transições de estado idênticas. Finalmente, o Log de Antecipação de Escrita (WAL) é estrito: as entradas são protegidas por CRC e encadeadas por hash. Se corrupção for detectada, o sistema é projetado para parar em vez de adivinhar. Embora essas medidas forneçam forte segurança, o sistema é explicitamente projetado como um sistema CP (Consistência/Tolerância a Partições), priorizando a segurança sobre a disponibilidade e aceitando que os efeitos colaterais serão ao menos uma vez em vez de estritamente uma vez apenas.
O Problema com o Consenso Padrão
Algoritmos de consenso são a espinha dorsal de sistemas distribuídos, permitindo que múltiplos servidores concordem com uma sequência de comandos. Bibliotecas implementando Raft e Paxos são amplamente usadas para esse propósito. No entanto, essas bibliotecas tipicamente focam apenas na replicação de log e consistência. Elas garantem que todos os nós concordem com a ordem das operações, mas não gerenciam as consequências dessas operações. Isso é frequentemente descrito como tratar a máquina de estado como uma 'caixa-preta'. A camada de consenso passa o comando para a camada de aplicação e considera seu trabalho feito.
Essa separação de preocupações se torna problemática quando a aplicação precisa interagir com o mundo exterior. Operações comuns incluem:
- Cobrar o cartão de crédito de um cliente.
- Enviar uma notificação por e-mail.
- Disparar um webhook para um serviço externo.
O perigo surge durante uma falha de líder. Imagine um líder recebe um comando para 'Cobrar $50'. Ele passa isso para a aplicação, que contata o gateway de pagamento e cobra o cartão com sucesso. No entanto, antes que o líder possa replicar a entrada de log para a maioria dos seguidores e comprometê-la, ele falha. Os seguidores não sabem que a operação foi completada. Quando um novo líder é eleito, ele vê a entrada não comprometida e a executa novamente. O cliente é cobrado duas vezes. Esta é a mentira da 'execução uma vez apenas' mencionada na documentação: garantir verdadeiramente a execução uma vez apenas na camada de consenso é incrivelmente difícil sem ajuda da aplicação ou um mecanismo especializado.
Como Chr2 Garante Segurança Contra Falhas
Chr2 aborda o problema integrando o gerenciamento de efeitos colaterais diretamente no mecanismo de consenso. Ele se afasta do modelo de caixa-preta para um sistema onde os efeitos colaterais são cidadãos de primeira classe. A biblioteca alcança isso através de uma combinação de quatro mecanismos técnicos específicos projetados para trabalhar em uníssono.
Caixa de Saída Replicada
A mudança fundamental em Chr2 é a introdução de uma Caixa de Saída Replicada. Em vez de executar um efeito colateral imediatamente e esperar que a entrada de log seja comprometida, Chr2 armazena a intenção como um estado 'pendente' no log replicado. Isso significa que a solicitação para realizar uma ação é replicada para outros nós assim como qualquer outra mudança de estado. No entanto, a execução real é desacoplada da entrada de log inicial. Apenas o líder designado tem permissão para executar esses efeitos pendentes, e ele o faz sob a proteção de um token de fencing. Este token atua como uma prova de autoridade, garantindo que apenas o líder atual válido possa disparar ações externas.
Fencing Durável e Prevenção de Zombies
Um risco significativo em sistemas distribuídos é o 'líder zombie'. Isso ocorre quando um líder é particionado da rede, presumido morto, e então repentinamente reaparece. Se ele ainda acredita ser o líder, ele pode tentar executar operações que já foram tratadas por seu sucessor. Chr2 impede isso usando Fencing Durável.
O sistema mantém um arquivo de manifesto que registra o maior número de 'visão' (essencialmente o mandato do líder). Quando um líder muda, este manifesto é atualizado usando uma sequência específica de operações: escrevendo em um arquivo temporário, forçando a sincronização para o disco (fsync) e então renomeando o arquivo para o nome final (substituição atômica). Isso garante que, mesmo se a energia for perdida durante a atualização, o estado permaneça consistente. Um líder antigo tentando acordar descobrirá que seu número de visão é menor que o manifesto persistido e se recusará a executar efeitos.
Contexto Determinístico para Replay
O replay do log é um requisito padrão para recuperar de falhas. No entanto, os efeitos colaterais frequentemente dependem de variáveis como timestamps ou números aleatórios. Se esses mudarem durante o replay, a máquina de estado pode acabar em um estado diferente do anterior. Chr2 resolve isso fornecendo um Contexto Determinístico. Quando o código da aplicação precisa realizar uma ação, ele recebe entradas específicas da camada de consenso:
- Uma semente determinística de Gerador de Números Aleatórios (RNG).
- O tempo exato do bloco do log.
Como essas entradas são fixadas pelo histórico do log, o replay do log sempre produzirá o mesmo resultado. Isso garante transições de estado 1:1.
Log de Antecipação de Escrita (WAL) Estrito
A integridade dos dados é primordial. Chr2 emprega um WAL Estrito. Cada entrada escrita no log é protegida por um CRC (Verificação de Redundância Cíclica) e encadeada por hash à entrada anterior. Isso cria uma cadeia de dados verificável. Se corrupção for detectada no meio do log, o sistema é projetado para parar imediatamente em vez de tentar adivinhar o que os dados faltantes poderiam ter sido. Essa abordagem 'fechada-em-falha' impede que a corrupção de dados se propague pelo sistema.
Os Compromissos
Como todo sistema de consenso forte, Chr2 faz escolhas de design que impactam o comportamento geral. O sistema é explicitamente projetado como um sistema CP (Consistência/Tolerância a Partições) sob o teorema CAP. Isso significa que, em caso de uma partição de rede, o sistema priorizará a consistência dos dados (evitando execuções duplicadas) sobre a disponibilidade. Aceitar a possibilidade de indisponibilidade permite que ele garanta fortes propriedades de segurança, como a prevenção de execução duplicada de efeitos colaterais.
O resultado prático disso é a garantia de ao menos uma vez para efeitos colaterais. Embora o mecanismo de consenso não garanta uma vez apenas absoluto, ele fornece as ferramentas necessárias para que a aplicação o faça. A caixa de saída replicada e o fencing garantem que a aplicação receba uma lista definitiva de efeitos a serem executados, permitindo que ela implemente lógica de deduplicação no lado do consumidor (sink-side deduplication) para alcançar a semântica uma vez apenas no nível de negócio.
Esta abordagem é uma mudança de paradigma em relação às soluções tradicionais que tentam forçar a execução uma vez apenas dentro do próprio consenso. Chr2 argumenta que garantir a execução uma vez apenas deve ser responsabilidade da camada de aplicação, enquanto a camada de consenso deve garantir a entrega ao menos uma vez de forma determinística e segura contra falhas.




