如何用 etcd 健壮性测试复现已知 issue 的回归场景并确认修复

发布时间:2026/9/13 21:10:13
如何用 etcd 健壮性测试复现已知 issue 的回归场景并确认修复 如何用 etcd 健壮性测试复现已知 issue 的回归场景并确认修复【免费下载链接】etcdDistributed reliable key-value store for the most critical data of a distributed system项目地址: https://gitcode.com/GitHub_Trending/et/etcd当你对 etcd 的一致性行为有疑虑——比如怀疑某个已知正确性 issue 在你的代码里回归了或者修复之后需要确认场景不再触发违规——etcd 仓库自带的 robustness 测试框架提供了一条可执行的路径每个已知的正确性/一致性问题在 tests/robustness/README.md 的 track record 表中都有登记其中多数配有专门的 make 目标如make test-robustness-issue14370可以只运行该 issue 对应的回归场景测试失败时会落盘一份报告用于确认失败是否与该 issue 的根因一致。这篇文章覆盖三个动作复现回归场景、分析失败报告确认根因、在修复后确认问题不再触发。前提是你有 etcd 源码仓库的一份本地 checkout并具备 git、Go、make 和网络访问make 目标会 clone 上游对应 tag、安装 gofail 工具、构建带 failpoint 的 etcd。健壮性回归测试的工作方式与适用对象健壮性测试把 etcd 集群的实际行为与一个简化模型比对创建指定配置的集群同时注入客户端流量put、range、txn 和各种 watch 模式与故障网络分区、节点 crash、磁盘故障记录全部客户端操作及其结果再对记录做验证发现违规时生成报告。详见 tests/robustness/README.md 的 How Robustness Tests Work 一节。track record 表登记了框架发现过的正确性 issue包括引入版本、发现方式和复现命令。其中配有复现目标的问题如下目标与所用构建版本取自 tests/robustness/Makefile问题场景 make 目标目标使用的构建单节点 crash 丢写 [#14370]make test-robustness-issue14370v3.5.4/tmp/etcd-v3.5.4-failpoints/bin高负载 crash 导致 revision 不一致 [#13766]make test-robustness-issue13766v3.5.2defrag 期间 crash 导致 revision 不一致 [#14685]make test-robustness-issue14685v3.5.5watch progress notification 与 stream 不同步 [#15220]make test-robustness-issue15220v3.5.7网络分区后 watch 时间回溯 [#15271]make test-robustness-issue15271v3.5.7stream 饥饿丢 watch 事件 [#17529]make test-robustness-issue17529v3.5.12 patchbeforeSendWatchResponsecompaction 期间 crash 导致 revision 回退 [#17780]make test-robustness-issue17780v3.5.13 patchcompactBeforeSetFinishedCompactcompaction on delete 时 watch 丢事件 [#18089]make test-robustness-issue18089v3.5.12 patchbeforeSendWatchResponsecompaction 同 revision 打开的 watch 丢 delete 事件 [#19179]make test-robustness-issue19179v3.5.17未来 revision 的 watch 返回异常 [#20221]make test-robustness-issue20221上游 commitbc47e771表中 Reproduction Script 列为空的问题如 #17247没有内置复现命令#14571 一行的备注是 Authorization is not covered#13766 的 Last reproduction commit 列记录为 Load not high enough表示该场景已无法按原方式复现。准备与副作用说明在仓库根目录执行 make 目标前先了解两个副作用issue 目标如test-robustness-issue14370依赖/tmp/etcd-v3.5.4-failpoints/bin这类产物Makefile 会先rm -rf对应的/tmp/etcd-*-failpoints目录再重新 clone 指定 tag、安装 gofail 并用 failpoint 构建。影响范围仅限该/tmp目录但会触发网络下载和一次完整构建。若按 README 的 Running locally 流程构建当前代码make gofail-enable→make build→make gofail-disablegofail-enable/gofail-disable会临时改写 server 相关目录下的源码以启停 failpoint 注入构建完成后要执行 disable 恢复源码。顶层 Makefile 第 5 行 include 了tests/robustness/Makefile因此所有test-robustness-*目标都直接在仓库根目录执行。复现已知 issue 的回归场景以 #14370单节点集群 crash 丢写为例make test-robustness-issue14370该目标实际展开为引自 tests/robustness/MakefileGO_TEST_FLAGS-v --runTestRobustnessRegression/Issue14370 --count 100 --failfast --bin-dir/tmp/etcd-v3.5.4-failpoints/bin make test-robustness要点--runTestRobustnessRegression/Issue14370只运行该 issue 对应的回归场景tests/robustness/main_test.go 中的TestRobustnessRegression遍历scenarios.Regression中的场景--count 100 --failfast表示最多重复 100 次、首个失败即停——复现本身具有概率性README 对 #14370 的表述是 After a couple of tries robustness tests should fail所以单次通过不等于问题不存在--bin-dir指向历史版本v3.5.4的 failpoint 构建即默认在引入 bug 的版本上验证可复现性。结果判定目标末尾是 echo Failed to reproduce || echo Successful reproduction。测试失败复现出 bug时打印Successful reproduction测试通过时打印Failed to reproduce。若测试失败日志中会出现Saving robustness test report行其path字段就是报告目录例如logger.go:146: 2025-08-01T22:54:26.7560900 INFO Saving robustness test report {path: /tmp/TestRobustnessRegression_Issue14370/1754056466755991000}注意报告默认只在测试失败时生成。可通过环境变量调整运行EXPECT_DEBUGtrue获取集群日志RESULTS_DIR改变报告落盘位置默认/tmpPERSIST_RESULTS让成功运行也保留报告GO_TEST_FLAGS透传go test参数README 推荐--count100 --failfast多次运行。以上均见 tests/robustness/README.md 的 Running locally 一节。分析失败报告确认与根因一致报告目录的结构README Analysing failure 一节server-*各 etcd 成员的数据目录可用来排查磁盘/内存损坏。其中member/wal可用tools目录下的etcd-dump-logs分析member/snap中的 bbolt 数据库文件db可用etcd-dump-db分析对应 tools/etcd-dump-logs、tools/etcd-dump-dbclient-*每个客户端的请求/响应转储。watch.json用于核对 watch API 保证operations.json是 KV 操作历史history.htmlKV 操作历史的可视化页面用于核对 KV API 保证。线性化违规KV 类如 #14370典型失败日志文档示例logger.go:146: 2025-08-01T22:54:26.5500900 INFO Validating linearizable operations {timeout: 5m0s} logger.go:146: 2025-08-01T22:54:26.7550900 ERROR Linearization illegal {duration: 205.05225ms} logger.go:146: 2025-08-01T22:54:26.7550900 INFO Skipping other validations as linearization failed main_test.go:122: linearization: illegal出现Linearization illegal后用浏览器打开报告目录中的history.html点击页面顶部的[ jump to first error ]跳到首个错误。文档示例中最后一个正确请求灰色连线是一个成功并获得 revision168的Put其后所有请求红色连线的 revision 却是167。etcd 保证 revision 单调不减revision 回退即构成 bug——这与 #14370 的根因进程 crash 导致最后一次写入丢失一致。Watch 违规如 #15271典型失败日志文档示例logger.go:146: 2024-05-08T10:50:15.8490200 ERROR Broke watch guarantee {guarantee: ordered, client: 4, revision: 3} validate.go:45: Failed validating watch history, err: broke Ordered - events are ordered by revision; an event will never appear on a watch if it precedes an event in time that has already been posted此时按日志中的 client 编号打开对应文件例如 client 4 的报告目录/client-4/watch.json。每行是一个 watch 请求的 JSON 转储查找Revision等于日志中 revision本例为 3的事件。文档示例中可以看到事件Revision先一路涨到799随后又出现了Revision为3的事件——watch 把旧 revision 重放了一遍违反Ordered保证与 #15271 的根因成员重连集群后重发 revision一致。以上日志和数值均为 tests/robustness/README.md 中的文档示例用于说明判断方法不是你每次运行必须得到的一模一样的输出。确认修复在修复后的构建上重跑回归场景issue make 目标的--bin-dir默认指向历史 tag 的构建用于确认bug 版本上仍可复现。要确认你的修复消除了问题用修复后的 failpoint 构建重跑同一场景先构建当前代码make gofail-enable→make build→make gofail-disable然后仿照 tests/robustness/Makefile 中 issue 目标的形式通过GO_TEST_FLAGS传入--run过滤与指向你自己构建产物的--bin-dirGO_TEST_FLAGS-v --runTestRobustnessRegression/Issue14370 --count 100 --failfast --bin-dir你的 failpoint 构建产物所在 bin 目录 make test-robustness其中你的 failpoint 构建产物所在 bin 目录替换为你本次make build产出 etcd 二进制的目录Makefile 中历史目标使用的是形如/tmp/etcd-v3.5.4-failpoints/bin的目录。判定测试通过对应目标形式下会打印Failed to reproduce表示该已知 issue 的场景在修复后的构建上没有再触发违规。注意复现是概率性的README 的维护流程Maintaining Bug Reproducibility要求变更后确认所有回归测试仍能捕获其目标 bug因此建议按--count 100 --failfast的量级重复验证而不是把单次通过当作绝对结论。用新验证器重新评估旧报告如果失败源于模型/验证器本身或你想用最新版校验逻辑重判一份历史失败报告把报告目录复制进tests/robustness/testdata/目录名任意只要与已有报告不冲突然后make test-robustness-reports该目标执行go test ./robustness/validate -v --count 1 --run TestDataReports对testdata下每份报告重新加载、验证并重新生成history.html见 tests/robustness/validate/validate_test.go。go test通过即所有报告通过当前验证器。限制README 明确说明报告格式不稳定并非所有旧报告都能用最新版本重新评估。CIProw上运行的失败报告需要先下载构建产物artifacts/results.zip并解压其中每个以TestRobustness为前缀的目录各含一份报告体积最大的目录通常对应失败场景README Re-evaluate existing report 一节。维护复现能力跟踪README 给出了仓库自身的收尾流程可作为确认修复的验收清单Establish Baseline大型改动前运行 track record 表中所有可复现的用例Verify Reproducibility改动完成后确认此前可复现的 bug 仍能被检测在 bug 构建上Update Tracking把 Last reproduction commit 列更新为新的 commit hash 与日期Update Commands若改动影响测试执行方式同步更新复现命令Gate Completion所有回归测试未继续捕获其目标 bug 前视为改动未完成。边界与限制报告默认只在失败时落盘成功运行默认不保留需要保留时设置PERSIST_RESULTS。报告格式不稳定旧报告可能无法用最新验证器重新评估。并非每个已知 issue 都有复现目标track record 表中 Reproduction Script 列为空的条目如 #17247没有内置命令#14571 备注为授权场景尚未覆盖。复现目标固定绑定特定历史 tag部分还打了 patchLast reproduction commit 列记录的是最后一次确认可复现的 commit如 #14370 为 2026 年 1 月的a438759复现成功不代表最新版本仍有该 bug反之亦然。运行 issue 目标会删除并重建对应的/tmp/etcd-*-failpoints目录、clone 上游代码并构建gofail-enable/gofail-disable会临时改写本地 server 源码执行前确认工作区没有未提交的修改。【免费下载链接】etcdDistributed reliable key-value store for the most critical data of a distributed system项目地址: https://gitcode.com/GitHub_Trending/et/etcd创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考