Page 74 - 《软件学报》2025年第7期
P. 74
陈元亮 等: 分布式系统动态测试技术研究综述 2995
在 HDFS 集群中, NameNode 负责存储并管理整个文件系统的元数据, 包括文件和目录的结构、权限, 以及每
个文件块所在的 DataNode 信息. DataNode 则是负责实际数据存储和管理的关键组件. 要触发这个缺陷, 需要至少
5 个关键步骤: 步骤 1, 通过配置动态更新指令挂载新卷, 扩容某些 DataNode 存储空间从而激活负载均衡器 Load
Balancer. 步骤 2, HDFS 接收到一系列数据新增存储请求后, Load Balancer 开始计算负载变化并相应更新存储分
布. HDFS 使用一个 clusterMap 记录已连接的 DataNode, 并使用一个 weightTree 对存储负载进行排序. 步骤 3, 如
果由于大负载数据删除变化请求导致树不平衡, 就会触发数据迁移. 步骤 4, 然而如果扩容的这个 DataNode 恰好
在此时因网络故障或其他原因导致下线, 就会触发这个数据迁移管理逻辑缺陷. 由于断开的 DataNode 的状态没有
及时在 clusterMap 中更新, 系统错误地认为该 DataNode 仍然在线. 因此, 迁移的数据计算会出错, 造成“热点”问
题 (某些节点的数据未被迁移出, 仍然保留在原处). 步骤 5, 任何针对这些 “热点” DataNode 的用户请求操作将会
延缓甚至中断处理. 这个逻辑缺陷会导致 HDFS 的关键数据服务挂起, 从而影响 HDFS 的可用性. 修复此缺陷的过
程如图 14 的第 14、15 行所示, 通过添加一个实时的状态检查器即可修复此缺陷.
分布式系统由于逻辑复杂性, 其代码实现过程中难免会出现缺陷. 一个小的代码实现错误很可能会放大影响
整个分布式系统, 导致严重的后果. 我们可以从这个案例中总结出一个重要的教训: 一些分布式系统的代码实现错
误往往隐藏在深层路径中, 要触发它们, 需要执行许多来自不同输入维度的操作, 包括系统配置修改、用户负载请
求以及故障注入. 在这个案例中, 至少需要 7 个步骤来产生足够频繁的负载变化, 从而启动数据迁移过程, 而在此
过程中, DataNode 节点恰好由于各种故障而下线. 因此, 未来可以设计高效的多维度输入策略, 以探索分布式系统
的深层次交互逻辑, 从而挖掘更多潜在的代码缺陷.
4.3 多维度输入测试初步实验
为了评估多维度输入策略对分布式系统动态测试的有效性, 我们集成了上述 4 个维度的输入生成方法, 挑选
了每个输入维度上测试性能较好的工具作为集成基础对象 (即系统配置生成工具 ECFuzz、用户请求负载生成工
具 DUPTester、节点消息生成工具 Tyr 和故障注入工具 Chronos), 形成了初步简单原型 MultiGen, 其架构如图 15
所示.
步骤1: 步骤2:
系统配置生成 用户请求生成 消息生成 错误注入
ECFuzz DUPTester LOKI CrashFuzz
系统配置 workload 节点消息 错序列
1. 逐个遍历 待测分布 2. 加载运行
式系统
3. 实时监控
步骤3:
崩溃漏洞 一致性 crash-recovery … 逻辑漏洞
检测器 检测器 检测器 检测器
图 15 MultiGen 测试流程
MultiGen 的测试过程主要分为 3 个步骤. 步骤 1, ECFuzz 基于待测分布式系统的默认配置文件, 通过参数依
赖感知的智能变异策略, 对配置中的关键参数运行多轮模糊测试, 生成大量系统配置测试输入文件, 并进行配置有
效性验证. 根据 ECFuzz 的实验结果, 该工具通常在 3–6 轮变异测试后测试过程趋于收敛. 因此, MultiGen 仅选择
前 6 轮生成的系统配置作为输入, 逐个遍历加载经过验证后的系统配置文件, 启动待测系统. 步骤 2, 待测系统启
动后, DUPTester、Tyr 以及 Chronos 分别并行生成 3 个不同维度的测试输入, 直接作为输入由待测系统加载运行.
步骤 3, 同时运行上述 4 个工具的缺陷检测器, 实时监控待测分布式系统的状态, 捕捉系统异常行为并输出系统缺

