Acabar con Raft: del consenso de ZooKeeper a Lux Quasar, de forma nativa
Cómo Hanzo Datastore sustituye el motor NuRaft bajo ClickHouse Keeper por Lux Quasar — consenso poscuántico y sin líder, enlazado directamente en el servidor C++ — y conserva la API de ZooKeeper que habla la replicación.

En esta página
Hanzo Datastore coordina hoy las tablas replicadas igual que ClickHouse: un Keeper compatible con ZooKeeper, embebido, que ejecuta Raft dentro del proceso del servidor. Funciona. También es el último componente clásico, con líder y pre-cuántico, de la pila. Este artículo cuenta cómo lo eliminamos — y por qué «acabar con ZK» no significa reescribir la replicación.
Desentramar Keeper: la API frente al motor
El instinto, al oír «sustituir ZooKeeper», es imaginar que hay que tocar cada Replicated*MergeTree. No tienes que hacerlo, porque ClickHouse Keeper ya son dos cosas separables trenzadas en un solo demonio:
-
La API de ZooKeeper — un árbol clave-valor linealizable, con nodos secuenciales, versiones y watches. En el fuente esto es
KeeperStorage, envuelto porKeeperStateMachine(src/Coordination/KeeperStateMachine.h,class IKeeperStateMachine : public nuraft::state_machine). Este es el contrato. Cada tabla replicada, cada consulta asystem.zookeepery cada elección de líder lo hablan. -
El motor de consenso — lo que toma un flujo de peticiones de escritura, logra que un quórum de nodos acuerde su orden y después llama a
commit(log_idx, data)sobre la máquina de estados en ese orden acordado. Hoy eso es NuRaft:KeeperServer::launchRaftServer(src/Coordination/KeeperServer.cpp) construye 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, instantáneas). No sabe, ni le importa, que debajo esté Raft. El motor es un valor que puedes sustituir, no un punto soldado a la API.
Así que: conserva la máquina de estados, sustituye el motor. La API de ZooKeeper de la que depende la replicación sobrevive intacta. Mueren NuRaft, la elección de líder y la exigencia de ejecutar un quórum Raft aparte.
Qué lo sustituye
El motor pasa a ser Quasar — el consenso sin líder, basado en un DAG y poscuántico de Lux. El trabajo de Quasar aquí es idéntico al de Raft: acordar el orden de un registro y avisar cuando una entrada es final. La diferencia está en cómo se pone de acuerdo: no hay un líder único al que conmutar, las firmas son ML-DSA en lugar de las clásicas, y la finalidad es un umbral de confianza, no la mayoría de un término fijo.
Y lo decisivo: Quasar no es un servicio en Go al que lancemos un proceso. Trae un motor C nativo con una ABI lista para C++ (libluxconsensus). El servidor de Datastore es C++. El motor se enlaza en el mismo proceso — sin sidecar, sin salto de red hasta un coordinador, sin un segundo lenguaje en tiempo de ejecución.
La juntura está demostrada — contra la máquina de estados real
Esto no es un boceto, y ya no es un modelo. Hemos construido un programa que enlaza la biblioteca real del servidor de ClickHouse (libdbms.a) y conduce la KeeperStateMachine<KeeperMemoryStorage> de producción — la clase exacta por la que se coordina ReplicatedMergeTree — entera sobre Quasar, con NuRaft fuera del camino de ordenación. Vive en el árbol de Datastore, en src/Coordination/examples/keeper_quasar_poc.cpp, y se compila y ejecuta en un host Linux real (aarch64, clang-21).
El flujo es fiel a cómo el despachador conduce NuRaft hoy — dos fases, preprocess cuando una petición se añade al registro y commit cuando el consenso fija 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
Ejecutado contra una secuencia de coordinación ReplicatedMergeTree de diez peticiones — registro de la réplica, incrementos del número de bloque, elección de líder — preprocesa cada petición, las ordena por Quasar, finaliza, hace commit en el KeeperStorage real y comprueba que el árbol resultante es exactamente el correcto, aplicado una vez cada elemento, en el orden del consenso:
== REAL Keeper state machine reached consensus on Quasar — zero Raft, zero ZK ensemble ==
Debajo queda la demostración mínima de la ABI de C (pkg/c/examples/cpp_consumer.cpp, make test-cpp), que enlaza libluxconsensus y finaliza un solo bloque — el mismo motor, sin la dependencia de ClickHouse. Las dos se pueden reproducir; el ejemplo de Datastore es opcional (-DENABLE_EXAMPLES=1 -DLUXCONSENSUS_DIR=...) y nunca entra en una compilación normal.
Ponlo sobre Keeper, uno a uno:
| Keeper / NuRaft hoy | Nativo en Quasar |
|---|---|
nuraft::raft_server ordena el registro | lux_chain_t ordena el registro |
KeeperLogStore / Changelog | el registro 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 en is_accepted |
| firmas clásicas, líder de término fijo | firmas ML-DSA, sin líder |
| un quórum ZK/Keeper aparte que operar | consenso en proceso, dentro del servidor |
KeeperStateMachine::commit es el punto de unión. NuRaft lo llama hoy; el controlador de Quasar llama mañana al método idéntico. La máquina de estados no puede distinguirlos — y esa es justo la propiedad que hace de esto un recambio y no una reescritura.
Por qué importa más allá de «poscuántico»
- Sin líder. Raft tiene un único líder elegido por término; si cae, las escrituras se paran hasta la reelección. El acuerdo sin líder de Quasar quita esa dependencia de cabeza de línea.
- Sin un segundo quórum que operar. La coordinación deja de ser un sistema aparte que aprovisionas, vigilas y del que haces copias de seguridad. Es el servidor.
- Poscuántico por construcción. Las firmas que protegen el acuerdo son ML-DSA, no curvas clásicas, de modo que un adversario cuántico futuro no puede falsificar los mensajes de consenso.
- Una sola historia de transporte. Encaja con el resto de la dirección — TCP/HTTP nativo ahora, ZAP a continuación, y las mismas primitivas de Lux que usan las cadenas.
Estado honesto
La arquitectura de arriba es real, y la prueba ya se ejecuta contra la KeeperStateMachine de producción — no contra un modelo —, compilada y en verde en un host Linux real. Lo que falta es el recambio dentro del motor: meter el backend de consenso Quasar dentro de KeeperServer, al lado de NuRaft, dejarlo por defecto y después llevar sobre él el resto de lo que hace KeeperServer — instantáneas, recuperación, caducidad de sesión, reconfiguración — con toda la batería de pruebas de Coordination en verde. Eso es trabajo de verdad, y no vamos a decirte que Raft ha desaparecido el día en que demostramos el camino de commit. Te decimos que la juntura aguanta con los tipos reales, que el punto de unión es KeeperStateMachine::commit, y que ahí se juega todo.
Cuando llegue, contrib/NuRaft/ y el motor Raft salen del árbol. La API de ZooKeeper se queda mientras la replicación la hable. Así se elimina el último componente pre-cuántico sin tocar un solo MergeTree.
- Datastore: github.com/hanzoai/datastore
- Consenso de Lux: github.com/luxfi/consensus
Leer más

Presentamos Hanzo Datastore: un motor OLAP preparado para lo poscuántico
Un almacén columnar derivado de ClickHouse, reconstruido en torno a la separación de almacenamiento y cómputo sobre Hanzo S3, optimizado con perfiles y en tiempo de enlace hasta quedar en aproximadamente la mitad de la memoria, sin gRPC y con una vía hacia la coordinación poscuántica sin líder.

El router es el registro
Hanzo Cloud no tiene ningún archivo OpenAPI versionado. La tabla de rutas en vivo es la fuente, proyectada de tres maneras, y un test de biyección hace fallar la compilación si alguna proyección se desvía. 1,362 operaciones en 963 rutas, generadas por proceso en el momento de la petición.

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.