Acabando com o Raft: do consenso ZooKeeper ao Lux Quasar, nativo
Como o Hanzo Datastore troca o motor NuRaft sob o ClickHouse Keeper pelo Lux Quasar — consenso pós-quântico e sem líder, ligado direto no servidor C++ — e mantém a API ZooKeeper que a replicação fala.

Nesta página
Hanzo Datastore coordena hoje as tabelas replicadas do jeito que o ClickHouse faz: um Keeper compatível com ZooKeeper, embutido, que roda Raft dentro do processo do servidor. Funciona. Também é o último componente clássico, com líder e pré-quântico, da pilha. Este post conta como a gente mata isso — e por que «matar ZK» não significa reescrever a replicação.
Desentrelaçar o Keeper: API versus motor
O reflexo, ao ouvir «substituir o ZooKeeper», é imaginar que dá para mexer em cada Replicated*MergeTree. Você não precisa, porque o ClickHouse Keeper já são duas coisas separáveis trançadas num daemon só:
-
A API ZooKeeper — uma árvore chave-valor linearizável, com nós sequenciais, versões e watches. No código isso é
KeeperStorage, embrulhado porKeeperStateMachine(src/Coordination/KeeperStateMachine.h,class IKeeperStateMachine : public nuraft::state_machine). Esse é o contrato. Cada tabela replicada, cada consulta asystem.zookeeper, cada eleição de líder fala com ele. -
O motor de consenso — o que pega um fluxo de pedidos de escrita, faz um quórum de nós concordar com a ordem e depois chama
commit(log_idx, data)na máquina de estados nessa ordem combinada. Hoje isso é o NuRaft:KeeperServer::launchRaftServer(src/Coordination/KeeperServer.cpp) constrói umnuraft::raft_server, umasio_service, umKeeperStateManagere umKeeperLogStore.
A observação limpa — a do Rich Hickey — é que KeeperStateMachine já está escrita contra a interface de consenso genérica (nuraft::state_machine: pre_commit, commit, rollback, snapshots). Ela não sabe, nem se importa, que o Raft está embaixo. O motor é um valor que você troca, não um ponto soldado na API.
Então: fique com a máquina de estados, troque o motor. A API ZooKeeper da qual a replicação depende sobrevive intacta. O que morre é o NuRaft, a eleição de líder e a obrigação de rodar um quórum Raft separado.
O que entra no lugar
O motor vira Quasar — o consenso sem líder, baseado em DAG e pós-quântico da Lux. O trabalho do Quasar aqui é idêntico ao do Raft: concordar com a ordem de um log e avisar quando uma entrada é final. A diferença está em como se concorda — nenhum líder único para failover, assinaturas ML-DSA no lugar das clássicas, e uma finalidade por limiar de confiança em vez da maioria de um termo fixo.
O ponto decisivo: Quasar não é um serviço em Go para o qual a gente dispara um processo. Ele traz um motor C nativo com uma ABI pronta para C++ (libluxconsensus). O servidor do Datastore é C++. O motor então se liga no mesmo processo — sem sidecar, sem salto de rede até um coordenador, sem uma segunda linguagem em tempo de execução.
A emenda está provada — contra a máquina de estados real
Isso não é um rascunho, e já não é um modelo. A gente construiu um programa que liga a biblioteca real do servidor ClickHouse (libdbms.a) e dirige a KeeperStateMachine<KeeperMemoryStorage> de produção — a classe exata pela qual o ReplicatedMergeTree se coordena — inteira em cima do Quasar, com o NuRaft fora do caminho de ordenação. Ele vive na árvore do Datastore em src/Coordination/examples/keeper_quasar_poc.cpp e é compilado e executado num host Linux de verdade (aarch64, clang-21).
O fluxo é fiel a como o despachante dirige o NuRaft hoje — duas fases, preprocess quando um pedido é anexado e commit quando o consenso fecha a ordem:
state_machine->preprocess(rfs, /*lock_mutex*/ true); // append-time, pre-consensus (≙ nuraft pre_commit)
auto buf = IKeeperStateMachine::getZooKeeperLogEntry(rfs); // the real ZooKeeper log entry
lux_chain_add_block(chain, &blk); // the entry rides Quasar (the slot raft_server occupies)
lux_consensus_process_vote(...); // validators agree — no leader
lux_consensus_is_accepted(chain, id, &accepted);
state_machine->commit(height, *buf); // finality → the real KeeperStorage mutates, in order
Rodado contra uma sequência de coordenação ReplicatedMergeTree de dez pedidos — registro da réplica, incrementos do número do bloco, eleição de líder — ele pré-processa cada pedido, ordena pelo Quasar, finaliza, faz commit no KeeperStorage real e confere que a árvore resultante está exatamente correta, aplicada uma vez cada, na ordem do consenso:
== REAL Keeper state machine reached consensus on Quasar — zero Raft, zero ZK ensemble ==
Embaixo fica a demonstração mínima da ABI C (pkg/c/examples/cpp_consumer.cpp, make test-cpp), que liga libluxconsensus e finaliza um único bloco — o mesmo motor, sem a dependência do ClickHouse. As duas são reproduzíveis; o exemplo do Datastore é opcional (-DENABLE_EXAMPLES=1 -DLUXCONSENSUS_DIR=...) e nunca entra num build normal.
Mapeie no Keeper, um para um:
| Keeper / NuRaft hoje | Nativo no Quasar |
|---|---|
nuraft::raft_server ordena o log | lux_chain_t ordena o log |
KeeperLogStore / Changelog | o log DAG do Quasar |
| eleição de líder do Raft | votação de confiança sem líder |
state_machine->commit(idx, data) | a mesma chamada, disparada em is_accepted |
| assinaturas clássicas, líder de termo fixo | assinaturas ML-DSA, sem líder |
| um quórum ZK/Keeper separado para operar | consenso no processo, dentro do servidor |
KeeperStateMachine::commit é o ponto de junção. O NuRaft chama isso hoje; o driver do Quasar chama o método idêntico amanhã. A máquina de estados não consegue perceber a diferença — e é exatamente essa propriedade que faz disso uma troca, e não uma reescrita.
Por que isso importa além do «pós-quântico»
- Sem líder. O Raft tem um único líder eleito por termo; a falha dele trava as escritas até a reeleição. O acordo sem líder do Quasar tira essa dependência de cabeça de fila.
- Sem um segundo quórum para rodar. A coordenação deixa de ser um sistema à parte que você provisiona, monitora e do qual faz backup. Ela é o servidor.
- Pós-quântico por construção. As assinaturas que protegem o acordo são ML-DSA, não curvas clássicas, então um adversário quântico futuro não consegue forjar mensagens de consenso.
- Uma história só de transporte. Isso se compõe com o resto da direção — TCP/HTTP nativo agora, ZAP em seguida, e as mesmas primitivas da Lux que as cadeias usam.
Status honesto
A arquitetura acima é real, e a prova agora roda contra a KeeperStateMachine de produção — não um modelo —, compilada e verde num host Linux de verdade. O que falta é a troca dentro do motor: introduzir o backend de consenso Quasar dentro do KeeperServer, ao lado do NuRaft, torná-lo o padrão e depois carregar o resto do que o KeeperServer faz — snapshots, recuperação, expiração de sessão, reconfiguração — com a suíte inteira de testes de Coordination verde. Isso é trabalho de verdade, e não vamos te dizer que o Raft sumiu no dia em que provamos o caminho de commit. Estamos te dizendo que a emenda segura contra os tipos reais, que o ponto de junção é KeeperStateMachine::commit, e que o jogo inteiro está aí.
Quando chegar, contrib/NuRaft/ e o motor Raft saem da árvore. A API ZooKeeper fica enquanto a replicação falar com ela. É assim que se mata o último componente pré-quântico sem tocar um único MergeTree.
- Datastore: github.com/hanzoai/datastore
- Consenso Lux: github.com/luxfi/consensus
Leia mais

Chegou o Hanzo Datastore: um motor OLAP pronto para o pós-quântico
Um armazém colunar derivado do ClickHouse, reconstruído em torno da separação entre armazenamento e computação no Hanzo S3, otimizado por perfil e em tempo de link até cerca de metade da memória, sem gRPC e com um caminho para a coordenação pós-quântica sem líder.

O roteador é o registro
A Hanzo Cloud não tem arquivo OpenAPI versionado. A tabela de rotas viva é a fonte, projetada de três jeitos, e um teste de bijeção faz o build falhar se alguma projeção desviar. 1,362 operações em 963 paths, geradas por processo na hora da requisição.

Jin 2.0: The Next Generation of Multimodal AI
Announcing Jin 2.0, a major upgrade to our unified multimodal AI architecture with expanded capabilities and improved performance.