Table of Contents

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 使用指南