TierRaftNode 使用指南(raft × TierWAL 产品节点)
TierRaftNode 是 raft × TierWAL 的完整产品节点装配入口:TierWAL 存储(持久化)+
raft 共识(RaftStateMachine)+ 提交应用管道(ApplyPipeline)+ 多源快照分发与反熵
(Swarm,可选)+ 宿主调度循环(快照压缩/发布/反熵周期)——一个装配器成节点,
节点成集群只差传输。
与 Core.Net 的关系:RaftStateMachine 是共识引擎(引擎与存储互不泄露布局),
本产品层把它与 TierWAL 接成开箱节点;共识引擎语义(复制完成档/读面/成员变更)
见 net.md §6。
快速上手
嵌入式·同进程(测试 / 单机进程内)
await using var hub = new InProcessTransportHub();
var id = NodeId.NewRandom();
var config = new ClusterConfig([new ClusterMember(id, "node-1")]);
var node = await TierRaftNodeBuilder.Create(id, TierFs.New("memory:"), config, myMachine)
.WithTransport(hub.Register(id)) // 注入现成传输
.StartAsync();
// 写入(复制完成档三选一——见 net.md §6.1)
await node.Raft.ReplicateAsync(command);
TCP 集群(真部署形态)
// 每节点各自执行:peers 表 = 全体成员(含自己)的监听地址
var node = await TierRaftNodeBuilder.Create(id, TierFs.New("local:///data/raft"), config, myMachine)
.WithClusterTransport(
listen: new IPEndPoint(IPAddress.Any, 7001),
peers: new Dictionary<NodeId, IPEndPoint>
{
[idA] = new(IPAddress.Parse("10.0.0.1"), 7001),
[idB] = new(IPAddress.Parse("10.0.0.2"), 7001),
[idC] = new(IPAddress.Parse("10.0.0.3"), 7001),
},
tune: o => o.WithReconnect(TimeSpan.FromMilliseconds(100), 2.0, TimeSpan.FromSeconds(1)))
.StartAsync();
内建形态经 Core.Net 装配器(ClusterBuilder)组装传输——传输配置全旋钮可调
(tune 管道:握手超时/重连退避/保活/请求回调/背压深度等),传输生命周期随节点。
传输形态怎么选
| 形态 | 方法 | 场景 |
|---|---|---|
| 注入现成传输 | WithTransport |
嵌入式同进程(InProcessTransportHub)、调用方自组装传输 |
| 内建 TCP 组装 | WithClusterTransport |
真网络部署——listen + peers 表 + 配置管道一行组装 |
二选一,双供给/零供给均 fail-fast(不偷偷选形态)。多节点同进程测试拓扑:
每节点一个 hub.Register(id) 注入即可。
加入既有集群(Standby 引导三档)
空盘节点不以完整配置启动,而是向既有集群宣告加入(JoinAsync 随启动编排):
| 档位 | Builder | 完成信号 | 典型场景 |
|---|---|---|---|
| Standby(缺省) | WithJoin(...) |
node.Raft.IsVoter 翻真 |
扩容新节点——追平自动晋级 |
| 永久只读副本 | WithJoinAsLearner(...) |
配置收敛含自身 | DP 观察副本——永不晋级不影响选举面 |
| 见证者(witness) | WithJoinAsWitness(...) + StartWitnessAsync() |
受理即完成 | 第三票防脑裂省全量副本 |
WithJoin / WithJoinAsLearner 各有 NodeId[](进程内/已互联传输)与
IPEndPoint[](TCP 端点拨号)两个重载;两形态下 join 都会向 leader 通告本端
监听地址(leader 回连复制),完成前对全部 bootstrap 对端补建链路(换届免疫)。
// 永久只读副本(TCP 端点拨号形态)
var dpNode = await TierRaftNodeBuilder.Create(idDp, fs, config, machine)
.WithClusterTransport(listen, peers)
.WithJoinAsLearner(idA, idB)
.StartAsync(ct);
// 见证者——无日志体/无状态机/无快照,非 TierRaftNode 形态:
var witness = await TierRaftNodeBuilder.Create(idW, fs, config, machine)
.WithClusterTransport(listenW, peersW)
.WithJoinAsWitness(idA, idB)
.StartWitnessAsync(ct);
// witness.Raft——投票/角色观测面;witness.Store——高水位断言流(LastLogIndex 单调不降)
witness 节点(TierRaftWitnessNode)以高水位断言流代替日志体:投票计入选主与提交
多数派、不存全量数据、永不自荐/晋级——MongoDB arbitrator / PolarDB witness 同位。
leader 侧单操作登记走 node.Membership.AddWitnessAsync(member)。
配置链(TierRaftNodeOptions)
| With | 默认 | 说明 |
|---|---|---|
WithWal |
TierWalOptions.Default | 存储参数(提交间隔/载体写穿档等——TierWAL 文档) |
WithRaft |
RaftOptions.Default | 选举窗/复制并发等(raft 引擎参数) |
WithApply |
ApplyPipelineOptions.Default | 应用管道参数 |
WithSwarm |
null(不装配) | SwarmOptions——多源快照分发;不装配 = 快照安装禁用 |
WithAntiEntropyInterval |
TimeSpan.Zero(关) | 反熵对账周期(仅 leader 发起) |
WithSnapshotGrowthThresholdEntries |
0(关) | 日志增长达阈值触发一体快照压缩(宿主调度) |
WithSnapshotBlockSize |
64KB | 快照内容块化粒度(Swarm 拉取/对账单元) |
WithHostLoopInterval |
30s | 宿主调度循环节拍 |
WithHighResolutionTimer |
true | Windows 提升定时器分辨率至 1ms(时序敏感路径) |
WithWorkerScheduler |
null(自建) | 引擎 worker 调度器共享注入——多节点同进程全部引擎共用一组线程(跨实例线程数恒定;经 WithWal 亦可) |
WithResourceProfile |
HighPerformance | 资源档位(见下节) |
资源档位(线程与内存地板)
嵌入式/多节点同进程/边缘部署的线程收缩入口(#505):
var options = TierRaftNodeOptions.Default
.WithResourceProfile(TierRaftResourceProfile.LowResource); // 或 WithWorkerScheduler(共享实例)
- HighPerformance(缺省):每引擎自建 2~4 条专用调度线程——单实例并发最优,现网行为零变化。
- LowResource:全部引擎(主日志/meta/快照)共用一组线程;Wal 未定制时几何随档收缩 (页 4MB→1MB、快照段 64MB→8MB、worker 消费者 2→1)——用户主权:Wal 任一字段定制过 则档位只补调度器缺省,几何不越权改写。
- 吞吐实测(8 实例并发写):自建 898~3845 ops/s vs 共享 2 线程 921~4246 ops/s(mem/local 双介质 持平略优),线程 -77%~-82%。
- Host 级作用域:
TierRaftHost多宿主同进程时,低资源组各自持 Host 专属调度器实例 (懒建、Dispose 随 Host)——宿主之间不互抢线程,无需手工装配。 - 活性地板不动:raft 共识循环/apply worker/复制 lane/传输收发循环的协议专用线程不受档位 影响(2026-09-03 活性判例——上池 = 心跳停发 = 集群冻结)。
- Witness 免疫:
TierRaftWitnessNode高水位存储为纯内存断言流(零引擎零线程)——无档位需求。
观测面
node.Raft.IsLeader/node.Raft.LeaderId/node.Raft.CommitIndex——角色与进度;node.Wal——TierWal 读面/水位(AllocatedIndex/PersistedIndex/SnapshotIndex);node.Swarm——多源组件(装配时非空)。
生命周期
StartAsync 返回即完整可用(存储恢复 → 适配 → raft 循环 → 宿主调度全就绪);
DisposeAsync 有界分段收尾:宿主循环 → raft → apply → 多源 → TierWal →(内建
形态)传输。每段超时告警不挂死。
反模式
- 双供给/零供给:
WithTransport与WithClusterTransport只能给一个;都不给直接抛。 - peers 表缺自己:内建 TCP 形态的 peers 表应含全体成员(含本节点)——成员制 拨号按表直连,缺表项 = 该成员不可达。
- 同步等待启动:
StartAsync()返回Task——用await,禁止GetAwaiter().GetResult()(线程池耗尽死锁风险)。 - witness 档走错入口:
WithJoinAsWitness须配StartWitnessAsync——StartAsync检测到 witness 档直接抛(witness 无日志体/状态机,非完整节点形态)。 - witness 配 autoPromote:
JoinAsync(asWitness: true, autoPromote: true)组合 fail-fast——witness 投票不存数据、永不转 voter。 - 成员表拨号不通告地址:TCP 形态
JoinAsync依赖本端监听地址通告 (builder 自解析WithClusterTransport的 listen;注入传输形态解析不出时显式传listenEndPoint)——缺通告 leader 无法回连,配置不收敛、Join 超时。 - Swarm 未装配却期待快照追赶:
WithSwarm缺省 = 快照安装传输面禁用,落后 follower 越过快照边界后无法追平——生产集群装配 Swarm。
故障注入本地验证(VALIDATIONS V 项的本地形态)
云上验证(真网络/kill -9/真时序)之外的本地确定性形态——V 项复跑与对抗场景族在任一介质等价驱动的抓手:
- 时钟缝:
nodeOptions.WithRaft(nodeOptions.Raft.WithClock(fake))——选举/心跳/复制计时由假钟快进 驱动(FakeTimeProvider.Advance,零真实睡等);墙钟跳变不误触发选举(单调钟守卫)。 注入假钟时节点自动新建同钟节拍注册表,无需手动配对。 - 传输缝:传输面
ITransportFaultInjector(延迟/分区/丢包/乱序,节点对级定向)——TCP/QUIC/InProcess 三介质等价(spec-12 §9.2)。 - 引擎缝/IO 缝:见
storage-engine.md§5.5 与fault-injection.md。 - 本地形态与云上形态的落账边界(哪个 V 项用哪种、判定口径):
scripts/cloud/VALIDATIONS.md各 V 项 "本地注入形态 / 云上形态"行。
想深入
- 共识引擎语义(复制完成档三选一/读面/成员变更/IRaftStore 需求面): Core.Net 使用指南 §6
- 产品层怎么保证 raft 论文核心(TierQueueReplica 的一致性语义/辖权 fencing/exactly-once 边界): raft-consistency.md
- 引擎内部如何满足论文五性质 + 高性能从哪来(架构与稳定性设计): raft-architecture.md
- 传输装配与配置全旋钮:Core.Net 使用指南 §1/§5
- 存储介质选型:TierFs 使用指南