在同一进程里终结 Raft:用无领导者的后量子共识 Lux Quasar 换下 ZooKeeper 的共识引擎
本文说明 Hanzo Datastore 如何把 ClickHouse Keeper 底下的 NuRaft 引擎换成 Lux Quasar。换上的是后量子、没有单一领导者的共识,直接链进同一套 C++ 服务器,复制层继续调用原来的 ZooKeeper 接口,调用方式保持不变。

本页内容
Hanzo Datastore 今天协调复制表的方式与 ClickHouse 相同:一个内嵌的、兼容 ZooKeeper 的 Keeper,在服务器进程里跑 Raft。它能工作。它也是这套栈里最后一块古典的、依赖领导者的、量子时代之前的部件。本文说明我们如何终结它,以及为什么“终结 ZK”并不意味着重写复制。
把 Keeper 拆开:接口与引擎
一听到“替换 ZooKeeper”,本能是想象要去碰每一个 Replicated*MergeTree。不必。ClickHouse Keeper 本来就是两件可以分开的东西,编进了同一个守护进程:
-
ZooKeeper 接口 — 一棵可线性化的键值树,带顺序节点、版本和监视。源码里它是
KeeperStorage,由KeeperStateMachine包着(src/Coordination/KeeperStateMachine.h,class IKeeperStateMachine : public nuraft::state_machine)。这是契约。每张复制表、每一次system.zookeeper查询、每一次领导者选举,说的都是它。 -
共识引擎 — 接收一串写请求,让节点法定人数就其顺序达成一致,再按该顺序在状态机上调用
commit(log_idx, data)。今天这是 NuRaft:KeeperServer::launchRaftServer(src/Coordination/KeeperServer.cpp)构造出nuraft::raft_server、asio_service、KeeperStateManager和KeeperLogStore。
干净的观察,也就是 Rich Hickey 的那个观察:KeeperStateMachine 已经对着通用共识接口来写(nuraft::state_machine:pre_commit、commit、rollback,以及快照)。它不知道也不在乎底下是 Raft。引擎是可以换掉的值,不是焊死在接口上的位置。
所以:留下状态机,换掉引擎。 复制所依赖的 ZooKeeper 接口原样保留。死去的是 NuRaft、领导者选举,以及必须另跑一套 Raft 法定人数的要求。
用什么替换
引擎变成 Quasar,来自 Lux 的无领导者、基于有向无环图、后量子的共识。Quasar 在这里的工作与 Raft 相同:就日志顺序达成一致,并在一条记录成为最终结果时发出信号。不同的是达成一致的方式:没有单一领导者需要故障转移,用 ML-DSA 签名代替经典签名,用置信阈值的最终性代替固定任期里的多数。
关键在于,Quasar 不是我们用外壳调出去的 Go 服务。它交付的是带 C++ 可用二进制接口的原生 C 引擎(libluxconsensus)。Datastore 服务器是 C++。于是引擎链进同一进程:没有边车,没有到协调器的网络一跳,运行时也没有第二种语言。
接缝已经证明,对着真正的状态机
这不是草图,也不再是模型。我们写了一个程序,链接真正的 ClickHouse 服务器库(libdbms.a),驱动生产用的 KeeperStateMachine<KeeperMemoryStorage>,也就是 ReplicatedMergeTree 用来协调的那个类,全程跑在 Quasar 上,排序路径里没有 NuRaft。它位于 Datastore 树的 src/Coordination/examples/keeper_quasar_poc.cpp,并在真实的 Linux 主机上编译运行(aarch64,clang-21)。
这条流程忠实于分发器今天驱动 NuRaft 的方式:两个阶段,请求被追加时是 preprocess,共识将其顺序定稿时是 commit:
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
拿十个请求的 ReplicatedMergeTree 协调序列来跑,包括副本注册、块号递增、领导者选举。它预处理每个请求,经 Quasar 排序,定稿,提交到真正的 KeeperStorage,并断言得到的树完全正确,每条按共识顺序各应用一次:
== REAL Keeper state machine reached consensus on Quasar — zero Raft, zero ZK ensemble ==
其下是最小的 C 二进制接口演示(pkg/c/examples/cpp_consumer.cpp,make test-cpp),链接 libluxconsensus 并定稿单个块:同一台引擎,不依赖 ClickHouse。两者都可复现。Datastore 的例子是可选的(-DENABLE_EXAMPLES=1 -DLUXCONSENSUS_DIR=...),从不进入普通构建。
按一对一映射到 Keeper:
| 今天的 Keeper / NuRaft | Quasar 原生 |
|---|---|
nuraft::raft_server 为日志排序 | lux_chain_t 为日志排序 |
KeeperLogStore / Changelog | Quasar 的有向无环图日志 |
| Raft 领导者选举 | 无领导者的置信投票 |
state_machine->commit(idx, data) | 同一次调用,在 is_accepted 时触发 |
| 经典签名,固定任期的领导者 | ML-DSA 签名,没有领导者 |
| 为了运转而单独准备的 ZK/Keeper 法定人数 | 进程内、服务器内的共识 |
KeeperStateMachine::commit 是接合点。今天由 NuRaft 调用,明天由 Quasar 驱动调用同一个方法。状态机分辨不出差别,而这正是它属于替换、不属于重写的性质。
为什么这比“后量子”更要紧
- 没有领导者。 Raft 每个任期选出一个领导者,它一失败,写入就停到重新选举。Quasar 的无领导者协议去掉了这种队首依赖。
- 不必再跑第二套法定人数。 协调不再是你要单独供应、监视和备份的系统。它就是这台服务器。
- 构造上就是后量子。 保护协议的签名是 ML-DSA,不是经典曲线,未来的量子对手无法伪造共识消息。
- 传输只有一个故事。 它与其余方向合在一起:现在是原生 TCP/HTTP,下一步是 ZAP,以及各条链正在使用的同一套 Lux 原语。
如实的现状
上面的架构是真的,证明现在跑在生产用的 KeeperStateMachine 上,不是模型,并在真实 Linux 主机上构建通过。剩下的是引擎内部的替换:在 KeeperServer 内部、与 NuRaft 并排放入 Quasar 共识后端,把它设为默认,再把 KeeperServer 还在做的事,快照、恢复、会话过期、重新配置,在整套 Coordination 测试变绿的前提下搬上去。这是真工作。我们不会在证明提交路径的那天告诉你 Raft 已经消失。我们告诉你的是,接缝对着真实类型站得住,接合点是 KeeperStateMachine::commit,这就是全部关键。
它落地时,contrib/NuRaft/ 和 Raft 引擎离开这棵树。只要复制还在说 ZooKeeper 接口,接口就留下。这就是不碰任何一个 MergeTree、却终结最后一块前量子部件的办法。
- Datastore: github.com/hanzoai/datastore
- Lux 共识: github.com/luxfi/consensus
继续阅读

今日正式发布 Hanzo Datastore:面向后量子时代的列式 OLAP 分析引擎
由 ClickHouse 派生的列式数仓,围绕 Hanzo S3 上的存储与计算分离重新构建,经配置文件引导优化与链接时优化后,常驻内存大约降到一半,并移除了 gRPC,同时留出通往无主后量子协调的路径。

路由器就是注册表
Hanzo Cloud 没有签入的 OpenAPI 文件。活的路由表才是源头,以三种方式投影,任一投影漂移,双射测试就让构建失败。963 条路径上的 1,362 个操作,在请求时按进程生成。

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.