5Draft(五帝)测试报告

5Draft(五帝)测试报告

报告日期:2026-09-05 | 测试版本:commit 7818ff1 | 报告人:5Draft 团队

项目地址:https://gitee.com/galaxy_0/5d-raft.git


一、测试概述

1.1 测试目的

验证 5Draft 预测性健康感知 Raft 的核心功能正确性,覆盖:

  • 趋势分析(劣化检测、毛刺过滤、预测钳制)
  • 消息编解码(精度、脏数据降级、边界处理)
  • 主动调度(连续计数触发、分差门禁、乒乓抑制)
  • 健康感知投票(Lease 有效择优 / 失效回退)
  • HealthMonitor 真实 CPU 记账(线程注册/注销、负载下降/恢复)
  • 仿真集群端到端禅让闭环
  • 真实 NuRaft 集群上的主动禅让
  • 全链路真实验证(无 Mock:真实集群 + 真实 CPU 压力触发禅让)

1.2 测试范围

层次 测试程序 验证目标
单元测试 unit_tests 各模块函数级正确性
仿真集成 5draft_demo 无网络依赖的闭环行为验证
真实集成 nuraft_demo 真实 NuRaft 集群 + 混沌注入禅让
全链路验证 nuraft_real_test 真实 CPU 压力触发禅让(无 Mock)

1.3 测试环境

项目
操作系统 WSL2 Debian (kernel 6.18.33.2-microsoft-standard-WSL2)
编译器 g++ 14.2.0 (Debian 14.2.0-19)
构建工具 CMake 3.31.6
在线逻辑核数 36
构建类型 Release
代码版本 commit 7818ff1

二、单元测试结果

程序./build/unit_tests退出码 :0 | 总用例数 :31 | 通过 :31 | 失败:0

2.1 趋势分析模块(5 项)

用例 结果 验证点
Trend/持续劣化: 一阶导为负 ✅ PASS 健康分持续下降时 H′ < 0
Trend/持续劣化: 预测分低于当前分 ✅ PASS H_pred = H + 4·H′ < H
Trend/瞬态毛刺: 恢复后预测分不过度悲观 ✅ PASS 单周期暴跌后恢复,pred > 0.7
Trend/瞬态毛刺: 当前分恢复 ✅ PASS H 恢复至 0.9
Trend/钳制: 预测分落在 0,1 ✅ PASS 快速上升场景 pred 被钳制

2.2 消息编解码模块(11 项)

用例 结果 验证点
Codec/正常解码 ✅ PASS "0.83,-0.02,0.003" 正确解析
Codec/数值一致 ✅ PASS 全精度(setprecision 15)往返一致
Codec/空串拒绝 ✅ PASS 空串返回 false
Codec/脏数据拒绝 ✅ PASS "abc,def" 返回 false
Codec/负数 h 钳制为 0 ✅ PASS h = -0.5 → 0.0
Codec/超大 h 钳制为 1 ✅ PASS h = 5.0 → 1.0
Codec/多余数值字段取前 3 个 ✅ PASS "0.5,0.1,0.01,0.9" 取前 3
Codec/仅 2 个字段拒绝 ✅ PASS "0.5,0.1" 返回 false
Codec/空格容忍 ✅ PASS " 0.5 , 0.1 , 0.01 " 解析成功
Codec/非数字多余字段拒绝 ✅ PASS "0.5,0.1,0.01,extra" 返回 false
Codec/NaN 拒绝 ✅ PASS "nan,0.0,0.0" 返回 false
Codec/Inf 拒绝 ✅ PASS "inf,0.0,0.0" 返回 false

2.3 主动调度模块(4 项)

用例 结果 验证点
Scheduler/连续2次不触发 ✅ PASS consecutive_required=3,2 次不触发
Scheduler/连续3次触发禅让给最优 Peer ✅ PASS 第 3 次触发 transfer_leadership(2)
Scheduler/分差不足不触发禅让 ✅ PASS diff=0.02 < threshold=0.08,不触发
Scheduler/差值回落重置计数(乒乓抑制) ✅ PASS 差值回落后计数清零,不再触发

2.4 投票决策模块(3 项)

用例 结果 验证点
Vote/Lease 有效且候选人更差 → 拒绝 ✅ PASS 候选人 pred < Leader pred + threshold
Vote/Lease 有效但候选人显著更优 → 授票 ✅ PASS diff=0.10 > 0.08,授票
Vote/Lease 失效 → 回退标准 Raft 授票 ✅ PASS lease_valid=false 时直接授票

2.5 HealthMonitor 模块(4 项)

用例 结果 验证点
HealthMonitor/RTT 200ms 评分归一化到 0 ✅ PASS net 权重 1.0,RTT=200ms → score=0 → H<0.1
HealthMonitor/Reset 清零导数 ✅ PASS Reset 后 h1=h2=0
HealthMonitor/注册负载线程后 CPU 可用率真实下降 ✅ PASS 满核施压后 CPU < 0.80
HealthMonitor/卸载负载后 CPU 可用率恢复 ✅ PASS 卸载后 CPU > 施压期

2.6 仿真集群端到端(3 项)

用例 结果 验证点
SimCluster/端到端: 劣化 Leader 主动禅让 ✅ PASS Leader 0 → 1,pred diff=0.56
SimCluster/端到端: 禅让给最健康节点 node1 ✅ PASS 禅让目标为预测分最高的节点
SimCluster/端到端: 禅让后任期递增 ✅ PASS term 1 → 2

2.7 单元测试汇总

复制代码
==== 31 checks, 0 failures ====

三、仿真集群演示结果

程序./build/5draft_demo退出码:0

场景 1:Leader 缓慢劣化(内存泄漏式)

  • 输入:Leader node0 健康分从 0.90 逐步下降至 0.35,Follower node1=0.90、node2=0.85
  • 预期:连续 3 个周期预测分显著落后 → 主动禅让
  • 实际5Draft: Leader 0 主动禅让给 1 (pred diff=0.56, term=1)
  • 结论:✅ 成功触发预测性禅让,新 Leader = node1

场景 2:Leader 瞬态抖动(单周期暴跌后恢复)

  • 输入:Leader 健康分单周期跌至 0.30 后立即恢复 0.90
  • 预期:二阶导数识别为触底反弹(H″>0),连续计数不累积 → 不切换
  • 结论:✅ 瞬态抖动被二阶导数 + 连续计数抑制,未发生切换

场景 3:RequestVote 健康感知

子场景 预期 实际
Lease 有效,弱候选人挑战健康 Leader 拒绝 ✅ 拒绝
Lease 有效,强候选人挑战劣化 Leader 授票 ✅ 授票
Lease 失效(Leader 失联) 回退标准 Raft 授票 ✅ 授票

结论:✅ 全部符合预期


四、真实 NuRaft 集群演示结果

程序./build/nuraft_demo退出码:0 | 端口:25011~25013

测试过程

  1. 启动 3 个真实 NuRaft 节点,组阁成功:初始 Leader = node1,term=1
  2. 对 Leader node1 注入混沌劣化健康:h=0.35, h′=-0.05, pred=0.15
  3. Follower 保持真实健康,心跳 meta 持续交换

关键日志(真实输出)

复制代码
[INFO]  集群就绪,初始 Leader = node1,term=1
[WARN]  5Draft node 1 进入混沌演练:自身健康被注入为 h=0.35 h'=-0.05 pred=0.15
[INFO]  已对 Leader node1 注入劣化健康(pred≈0.15),等待 5Draft 主动禅让...
[INFO]  5Draft: Leader 1 主动禅让给 3 (pred diff=0.723977, term=1)
[WARN]  [NuRaft] Server is elected as leader for term 2
[INFO]  ===== 禅让成功:Leader node1 → node3(新 term=2)[PASS]

验证点

检查项 结果
真实 NuRaft 集群组阁成功
混沌注入劣化健康后 Follower 预测分更优 ✅ (diff=0.724)
ActiveScheduler 调用 yield_leadership 禅让
新 Leader node3 当选,term 1→2,三节点一致

五、全链路真实验证结果(无 Mock)

程序./build/nuraft_real_test退出码 :0 | 核心特点:不注入任何健康数据,全程真实采集

5.1 验证方案

#mermaid-svg-NT3SkVgyYoRi2QT6{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NT3SkVgyYoRi2QT6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NT3SkVgyYoRi2QT6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NT3SkVgyYoRi2QT6 .error-icon{fill:#552222;}#mermaid-svg-NT3SkVgyYoRi2QT6 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NT3SkVgyYoRi2QT6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NT3SkVgyYoRi2QT6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NT3SkVgyYoRi2QT6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NT3SkVgyYoRi2QT6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NT3SkVgyYoRi2QT6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NT3SkVgyYoRi2QT6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NT3SkVgyYoRi2QT6 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NT3SkVgyYoRi2QT6 .marker.cross{stroke:#333333;}#mermaid-svg-NT3SkVgyYoRi2QT6 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NT3SkVgyYoRi2QT6 p{margin:0;}#mermaid-svg-NT3SkVgyYoRi2QT6 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-NT3SkVgyYoRi2QT6 .cluster-label text{fill:#333;}#mermaid-svg-NT3SkVgyYoRi2QT6 .cluster-label span{color:#333;}#mermaid-svg-NT3SkVgyYoRi2QT6 .cluster-label span p{background-color:transparent;}#mermaid-svg-NT3SkVgyYoRi2QT6 .label text,#mermaid-svg-NT3SkVgyYoRi2QT6 span{fill:#333;color:#333;}#mermaid-svg-NT3SkVgyYoRi2QT6 .node rect,#mermaid-svg-NT3SkVgyYoRi2QT6 .node circle,#mermaid-svg-NT3SkVgyYoRi2QT6 .node ellipse,#mermaid-svg-NT3SkVgyYoRi2QT6 .node polygon,#mermaid-svg-NT3SkVgyYoRi2QT6 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NT3SkVgyYoRi2QT6 .rough-node .label text,#mermaid-svg-NT3SkVgyYoRi2QT6 .node .label text,#mermaid-svg-NT3SkVgyYoRi2QT6 .image-shape .label,#mermaid-svg-NT3SkVgyYoRi2QT6 .icon-shape .label{text-anchor:middle;}#mermaid-svg-NT3SkVgyYoRi2QT6 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NT3SkVgyYoRi2QT6 .rough-node .label,#mermaid-svg-NT3SkVgyYoRi2QT6 .node .label,#mermaid-svg-NT3SkVgyYoRi2QT6 .image-shape .label,#mermaid-svg-NT3SkVgyYoRi2QT6 .icon-shape .label{text-align:center;}#mermaid-svg-NT3SkVgyYoRi2QT6 .node.clickable{cursor:pointer;}#mermaid-svg-NT3SkVgyYoRi2QT6 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NT3SkVgyYoRi2QT6 .arrowheadPath{fill:#333333;}#mermaid-svg-NT3SkVgyYoRi2QT6 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NT3SkVgyYoRi2QT6 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NT3SkVgyYoRi2QT6 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NT3SkVgyYoRi2QT6 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NT3SkVgyYoRi2QT6 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NT3SkVgyYoRi2QT6 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NT3SkVgyYoRi2QT6 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NT3SkVgyYoRi2QT6 .cluster text{fill:#333;}#mermaid-svg-NT3SkVgyYoRi2QT6 .cluster span{color:#333;}#mermaid-svg-NT3SkVgyYoRi2QT6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NT3SkVgyYoRi2QT6 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NT3SkVgyYoRi2QT6 rect.text{fill:none;stroke-width:0;}#mermaid-svg-NT3SkVgyYoRi2QT6 .icon-shape,#mermaid-svg-NT3SkVgyYoRi2QT6 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NT3SkVgyYoRi2QT6 .icon-shape p,#mermaid-svg-NT3SkVgyYoRi2QT6 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NT3SkVgyYoRi2QT6 .icon-shape .label rect,#mermaid-svg-NT3SkVgyYoRi2QT6 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NT3SkVgyYoRi2QT6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NT3SkVgyYoRi2QT6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NT3SkVgyYoRi2QT6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 真实 3 节点 NuRaft 集群
基线期 3s

真实采集 CPU/内存
对 Leader 施加真实 CPU 压力

36 线程 × 85% 占空
Leader CPU 真实下滑

内核记账 /proc/self/task
心跳 meta 携带真实健康
ActiveScheduler 判定

pred diff=0.82
yield_leadership 主动禅让
卸载压力

旧 Leader CPU 真实恢复

5.2 实测数据时间线

阶段 时刻 node1 角色 node1 H node1 H′ node1 pred node1 CPU 说明
基线 t=3.00s Leader 0.93 0.00 0.93 1.00 三节点健康一致
施压 t=0.50s Follower 0.51 -0.09 0.13 0.15 已禅让,node2 为新 Leader
恢复 t=4.00s Follower 0.93 0.00 0.93 1.00 压力卸载后恢复

施压后仅 0.5s(一个采样间隔)内即完成禅让,远早于任何 election timeout。

5.3 六项检查结果

检查项 通过标准 实测值 结果
检查1:集群组阁 Leader 选出,term=1 node1, term=1 ✅ PASS
检查2:基线健康 CPU > 0.9, H > 0.75 CPU=1.00, H=0.934 ✅ PASS
检查3:施压降载 CPU < 0.5 CPU=0.153(内核记账) ✅ PASS
检查4:预测下滑 pred 下降 > 0.15 0.934 → 0.130 ✅ PASS
检查5:主动禅让 Leader 切换,term 递增 node1→node2, term 1→2 ✅ PASS
检查6:卸载恢复 CPU > 0.9 CPU=1.00 ✅ PASS

5.4 真实关键日志

复制代码
[INFO]  本机在线逻辑核数:36,将对 Leader 施加 36 线程 × 85% 占空比的真实 CPU 压力
[INFO]  [检查2] 基线期 Leader 真实 CPU 可用率=1、健康分 H=0.933951  [PASS]
[INFO]  5Draft: Leader 1 主动禅让给 2 (pred diff=0.820605, term=1)
[INFO]  [检查3] 施压后 Leader 真实 CPU 可用率最低降至 0.15305(内核记账,非注入)  [PASS]
[INFO]  [检查4] Leader 真实预测健康分最低降至 0.13001(基线 H=0.933951)  [PASS]
[INFO]  [检查5] 主动禅让发生:node1 → node2,term 1 → 2  [PASS]
[INFO]  [检查6] 卸载后旧 Leader 真实 CPU 可用率恢复至 1  [PASS]
[INFO]  ===== 真实验证结论:5/5 项检查通过,整体 [PASS] =====

六、测试覆盖率分析

6.1 模块覆盖

模块 单元测试 仿真验证 真实集群验证 全链路验证
TrendAnalyzer ✅ 5 项 --- ---
MessageExtension ✅ 11 项 ✅(编解码链路)
ActiveScheduler ✅ 4 项
VoteDecider ✅ 3 项
HealthMonitor ✅ 4 项 --- --- ✅(真实 CPU)
FiveDraftNode ---
NuraftNode --- ---
IRaftServer 适配 ---

6.2 功能点覆盖

功能点 覆盖情况
健康分加权计算 ✅ HealthMonitor 权重测试
一阶/二阶导数趋势分析 ✅ TrendAnalyzer 测试
预测分外推与钳制 ✅ TrendAnalyzer 钳制测试
消息编解码精度 ✅ setprecision 15 往返一致
脏数据/边界数据降级 ✅ 11 项编解码边界测试
连续计数防抖 ✅ Scheduler 连续 2/3 次测试
分差阈值门禁 ✅ Scheduler 分差不足测试
乒乓抑制 ✅ Scheduler 差值回落重置测试
Lease 有效择优投票 ✅ VoteDecider 测试
Lease 失效回退 Raft ✅ VoteDecider 测试
真实 CPU 内核记账 ✅ HealthMonitor 线程注册测试 + 全链路验证
负载卸载后恢复 ✅ HealthMonitor 恢复测试 + 全链路验证
主动禅让(仿真) ✅ SimCluster 端到端
主动禅让(真实集群,注入) ✅ nuraft_demo
主动禅让(真实集群,无 Mock) ✅ nuraft_real_test
禅让后任期递增 ✅ 仿真 + 真实集群
禅让目标为最健康节点 ✅ SimCluster

七、已知限制与未覆盖项

项目 说明
macOS 健康采集 HealthMonitor 在 macOS 上未实现平台接口,返回中性默认值并降级;未在 macOS 上测试
网络 RTT 维度 全链路验证中网络分固定为 0.8(loopback),未覆盖真实网络抖动场景
大规模集群 仅在 3 节点集群上验证,未测试 >5 节点场景
长时稳定性 单次运行约 30~60 秒,未做 24h+ 长时稳定性测试
并发压力测试 ActiveScheduler 多线程并发调用 UpdatePeerHealth + OnLeaderTick 的压力测试未覆盖
成员变更场景 未测试禅让过程中伴随 add_srv/remove_srv 的并发场景

八、结论

8.1 总体结果

测试层次 用例数 通过 失败 通过率
单元测试 31 31 0 100%
仿真集群演示 3 场景 3 0 100%
真实 NuRaft 演示 1 1 0 100%
全链路真实验证 6 项检查 6 0 100%
合计 41 41 0 100%

8.2 核心结论

  1. 趋势分析正确:一阶导/二阶导能区分持续劣化与瞬态抖动,预测分钳制在 0,1
  2. 编解码健壮:全精度序列化,脏数据/越界/NaN/Inf 均正确降级
  3. 主动调度有效:连续计数 + 分差阈值 + 乒乓抑制三层防抖,仅在持续显著劣化时禅让
  4. 投票安全:Lease 失效自动回退标准 Raft,不破坏 Raft Safety
  5. 真实 CPU 记账可信:注册线程后 CPU 可用率真实下降(1.00→0.15),卸载后恢复(→1.00)
  6. 全链路禅让成功:真实 36 核 CPU 压力下,Leader 在 500ms 内主动禅让,term 1→2,无 Mock

8.3 建议

  1. 补充 macOS 平台健康采集实现
  2. 增加 >5 节点集群与成员变更并发的集成测试
  3. 增加长时稳定性测试(24h+)
  4. 增加 ActiveScheduler 多线程并发压力测试
  5. 在真实网络环境(非 loopback)下验证网络 RTT 维度的健康感知投票

附录:测试复现命令

bash 复制代码
# 构建
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)

# 1. 单元测试
./build/unit_tests

# 2. 仿真集群演示
./build/5draft_demo

# 3. 真实 NuRaft 集群演示(混沌注入)
./build/nuraft_demo

# 4. 全链路真实验证(无 Mock,推荐)
./build/nuraft_real_test
相关推荐
UIU1141 小时前
scanf与cout的误区:探究其内部的机制
c++·学习·c#·scanf
闻缺陷则喜何志丹1 小时前
【栈 运算系统】P3719 [AHOI2017初中组] rexp|普及+
c++·算法··洛谷·运算系统
一技安身1 小时前
【信创】外网aarch64终端安装deepseek Ragflow 迁移至内网银河麒麟服务器
运维·服务器
bnmoel1 小时前
C++ 基础入门篇(一):命名空间,输入&输出,缺省参数,函数重载
c++·函数重载·语法·命名空间·缺省参数
Zixhy2 小时前
多点巡检机器人项目技术总结
linux·c++·机器人·自动驾驶
M哥支付2 小时前
快捷支付 VS 网关支付 安全对比
服务器·网络·其他·微信·金融
2501_928996222 小时前
Agent 开发的 API 选型:从 Function Calling 到多模型协作的中科热备底层逻辑
服务器·重构·gitlab
非凡ghost3 小时前
AI修图不“造假“,摄影师的出片效率加速器
服务器·前端·人工智能·电脑
Ruiery4 小时前
Linux 6.6内核 PCIe 深度解析(十):PCIe Port Driver(portdrv)— 一个物理 Port,拆出五个逻辑服务
linux·运维·服务器