线上只失败过一次,怎样把故障变成能重放的测试?
设想一笔已确认的转账在主节点切换后查不到了。沿着六段工程讲解,把事故拆成可以保存的输入、可以删减的操作和必须成立的性质,再检验修复是否真的触达故障。
先把一次故障变成一份输入
假设一个转账请求在主节点切换时消失。保存请求内容,明天重发一次,系统很可能一直是好的。Wilson 的模拟把下一次随机选择也交给受控发生器,种子随输入保存。这样,团队才能让同一套实现再次走过相同的事件顺序。先检查模拟器自身的可重复性很重要:若同样输入在两次运行后连下一次随机数都不同,所谓重放就已经走岔了。能重放模拟中的一次故障,仍取决于模拟有没有包括导致线上故障的那种外部事件。
原文与时间戳 · 2
the seed of that random number generator becomes part of the input of the programif those don't match exactly we know there was a determinism failure复现一千步以后,哪些步必须留下?
把线上操作序列原封不动交给开发者,仍然很难解释哪里错了。Hughes 为每个 API 调用写一个较小的状态转换模型,生成调用序列,再从一个失败序列里不断删掉不必要的调用。Halloway 的生成式规约补上另一个问题:生成器能给出作者没想到的数据,但仍需一个有区分力的性质来识别错误。如果只扣了甲的钱、没有给乙入账,「两个账户合计不变」会失败。如果两边都没动,这条检查反而会通过。要抓住后一种错,还得按已确认的转账 ID 核对两笔应有的变动。缩减时应该保留下来的,是能让具体检查失败的步骤。
原文与时间戳 · 3
we generate a minimal failing examplefor each API call we define a state transition functionwhen you spec something, Clojure can generate example data for you一条反例,究竟反驳了什么?
Wayne 先写下「余额不得透支」,让 TLC 在模型里寻找违规状态,由此拿到一条具体的交错路径。Parlar 用 Alloy 检查设计时则碰到另一种可能:反例之所以惊人,是因为模型忘了写一个约束。看到反例后,可以沿同一条路径分别问:规则允许这一步吗?当前实现也允许吗?前者帮你修正规约,后者才可能成为实现级重放用例。有限模型给出的轨迹不自动等于某一次线上事故。
原文与时间戳 · 2
find one that violated our invariant it also provided an error tracewe haven't been precise enough in our specification修完后,再让两种解释分一次胜负
旧种子现在会通过,至少有两种解释:错误被修好,或者触发路径不再被走到。Halloway 的调试方法是给猜想找一个不该观察到的结果。可以保留同一时序,把转账记录和账户合计也写入断言,然后有意放回那处可疑错误。如果用例仍然是绿的,首先要重审测试是否真的触达故障。这个实验把「我再没遇到它」变成一个别人可以反复试的判断。
原文与时间戳 · 2
you say I have a hypothesis it implies there's something I should not seethe hypothesis um is supported by the experiment but maybe you still don't have an answer读完再想一步
挑最近的一次偶发错误,写下要保存的输入、不能被删掉的一步,以及一个即便请求成功也可能被破坏的性质。现在把旧错误放回来:哪个检查应该失败?