Matar Raft: del consenso ZooKeeper al Lux Quasar nativo
Cómo Hanzo Datastore reemplaza el motor NuRaft que está debajo de ClickHouse Keeper por Lux Quasar — consenso poscuántico, sin líder, vinculado directo en el servidor C++ — y deja la API de ZooKeeper que la replicación sigue hablando.

En esta página
Hanzo Datastore coordina hoy las tablas replicadas como lo hace ClickHouse: un Keeper compatible con ZooKeeper, embebido, que corre Raft adentro del proceso del servidor. Funciona. También es el último componente clásico, con líder y previo a lo cuántico, que queda en el stack. Este post cuenta cómo lo matamos — y por qué «matar ZK» no quiere decir reescribir la replicación.
Desenredar Keeper: la API contra el motor
El reflejo, cuando se oye «reemplazar ZooKeeper», es pensar que hay que tocar cada Replicated*MergeTree. Ustedes no tienen que hacerlo, porque ClickHouse Keeper ya son dos piezas separables trenzadas en un solo demonio:
-
La API de ZooKeeper — un árbol clave-valor linealizable, con nodos secuenciales, versiones y watches. En el código esto es
KeeperStorage, envuelto porKeeperStateMachine(src/Coordination/KeeperStateMachine.h,class IKeeperStateMachine : public nuraft::state_machine). Ese es el contrato. Cada tabla replicada, cada consulta asystem.zookeepery cada elección de líder lo hablan. -
El motor de consenso — lo que agarra un flujo de solicitudes de escritura, consigue que un cuórum de nodos acuerde el orden y después llama a
commit(log_idx, data)en la máquina de estados, en ese orden ya acordado. Hoy eso es NuRaft:KeeperServer::launchRaftServer(src/Coordination/KeeperServer.cpp) arma unnuraft::raft_server, unasio_service, unKeeperStateManagery unKeeperLogStore.
La observación limpia — la de Rich Hickey — es que KeeperStateMachine ya está escrita contra la interfaz de consenso genérica (nuraft::state_machine: pre_commit, commit, rollback, capturas). No sabe, ni le importa, que Raft esté abajo. El motor es un valor que ustedes pueden cambiar, no un punto soldado a la API.
Entonces: conserven la máquina de estados, reemplacen el motor. La API de ZooKeeper de la que depende la replicación queda intacta. Lo que muere es NuRaft, la elección de líder y la obligación de correr un cuórum Raft aparte.
Qué entra en su lugar
El motor pasa a ser Quasar — el consenso sin líder, basado en un DAG y poscuántico de Lux. El trabajo de Quasar acá es el mismo que el de Raft: ponerse de acuerdo en el orden de un log y avisar cuándo una entrada ya es final. La diferencia está en el cómo: no hay un líder único al que hacer failover, las firmas son ML-DSA en vez de las clásicas, y la finalidad es un umbral de confianza, no la mayoría de un término fijo.
Lo clave: Quasar no es un servicio en Go al que le lanzamos un proceso. Trae un motor C nativo con una ABI lista para C++ (libluxconsensus). El servidor de Datastore es C++. El motor se vincula en el mismo proceso — sin sidecar, sin salto de red a un coordinador, sin un segundo lenguaje en runtime.
La costura está probada — contra la máquina de estados real
Esto no es un borrador, y ya no es un modelo. Armamos un programa que vincula la biblioteca de verdad del servidor de ClickHouse (libdbms.a) y maneja la KeeperStateMachine<KeeperMemoryStorage> de producción — la clase exacta por la que se coordina ReplicatedMergeTree — entera sobre Quasar, con NuRaft fuera del camino de ordenamiento. Vive en el árbol de Datastore, en src/Coordination/examples/keeper_quasar_poc.cpp, y se compila y corre en un host Linux real (aarch64, clang-21).
El flujo es fiel a cómo el despachador maneja NuRaft hoy — dos fases, preprocess cuando una solicitud se agrega al log y commit cuando el consenso cierra su orden:
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
Corrido contra una secuencia de coordinación ReplicatedMergeTree de diez solicitudes — registro de la réplica, saltos del número de bloque, elección de líder — preprocesa cada solicitud, las ordena por Quasar, finaliza, hace commit en el KeeperStorage real y afirma que el árbol que queda es exactamente el correcto, aplicado una vez cada uno, en el orden del consenso:
== REAL Keeper state machine reached consensus on Quasar — zero Raft, zero ZK ensemble ==
Abajo está la demo mínima de la ABI de C (pkg/c/examples/cpp_consumer.cpp, make test-cpp), que vincula libluxconsensus y finaliza un solo bloque — el mismo motor, sin la dependencia de ClickHouse. Las dos se reproducen; el ejemplo de Datastore es opt-in (-DENABLE_EXAMPLES=1 -DLUXCONSENSUS_DIR=...) y nunca entra en un build normal.
Mírenlo sobre Keeper, uno a uno:
| Keeper / NuRaft actualmente | Quasar nativo |
|---|---|
nuraft::raft_server ordena el log | lux_chain_t ordena el log |
KeeperLogStore / Changelog | el log DAG de Quasar |
| elección de líder de Raft | votación de confianza sin líder |
state_machine->commit(idx, data) | la misma llamada, disparada al cumplirse is_accepted |
| firmas clásicas, líder de término fijo | firmas ML-DSA, sin líder |
| un cuórum ZK/Keeper aparte para operar | consenso en el proceso, adentro del servidor |
KeeperStateMachine::commit es el punto de unión. NuRaft lo llama hoy; el driver de Quasar llama mañana al mismo método. La máquina de estados no puede notar la diferencia — y esa es justo la propiedad que hace de esto un recambio y no una reescritura.
Por qué esto importa más allá de «post-cuántico»
- Sin líder. Raft tiene un solo líder electo por término; si se cae, las escrituras se frenan hasta la reelección. El acuerdo sin líder de Quasar saca esa dependencia de cabeza de línea.
- Sin un segundo cuórum que correr. La coordinación deja de ser un sistema aparte que ustedes aprovisionan, monitorean y respaldan. Es el servidor.
- Poscuántico de fábrica. Las firmas que protegen el acuerdo son ML-DSA, no curvas clásicas, así que un adversario cuántico de más adelante no puede falsificar mensajes de consenso.
- Una sola historia de transporte. Se compone con el resto del rumbo — TCP/HTTP nativo ahora, ZAP después, y las mismas primitivas de Lux que usan las cadenas.
Dónde estamos de verdad
La arquitectura de arriba es real, y la prueba ya corre contra la KeeperStateMachine de producción — no contra un modelo —, compilada y pasando en un host Linux real. Lo que falta es el recambio adentro del motor: meter el backend de consenso Quasar dentro de KeeperServer, al lado de NuRaft, volverlo el predeterminado y después subir el resto de lo que hace KeeperServer — capturas, recuperación, vencimiento de sesión, reconfiguración — con toda la suite de pruebas de Coordination en verde. Eso es trabajo de verdad, y no les vamos a decir que Raft ya no está el día en que probamos el camino de commit. Les decimos que la costura aguanta contra los tipos reales, que el punto de unión es KeeperStateMachine::commit, y que ahí está todo el juego.
Cuando entre, contrib/NuRaft/ y el motor Raft se van del árbol. La API de ZooKeeper se queda mientras la replicación la hable. Así se mata el último componente previo a lo cuántico sin tocar un solo MergeTree.
- Datastore: github.com/hanzoai/datastore
- Consenso Lux: github.com/luxfi/consensus
Leer más

Llegó Hanzo Datastore: un motor OLAP listo para la era poscuántica
Un depósito columnar heredado de ClickHouse, rearmado alrededor de la separación entre almacenamiento y procesamiento sobre Hanzo S3, optimizado por perfiles y en tiempo de enlace hasta cerca de la mitad de la memoria, con gRPC fuera y un camino hacia la coordinación poscuántica sin líder.

El enrutador es el padrón
Hanzo Cloud no guarda un archivo OpenAPI en el repositorio. La tabla viva de rutas es la fuente, proyectada de tres formas, y una prueba de biyección hace fallar el build si alguna proyección se corre. 1,362 operaciones en 963 rutas, generadas por proceso al momento del pedido.

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.