把能用的和不能用的并排摆出来
一句话总结
鉴别诊断不是只盯着失败样本,而是把成功样本并排摆在一起,只保留“存在于所有失败中、且不存在于任何成功中”的属性。
为什么需要它
“有的客户可以,有的客户不行。”这是现场最常听到的一句话,同时也是最好的消息。因为有一部分是正常的,就意味着有可以比较的对照组。
但大多数人放弃了这个消息,只去钻研失败请求的日志。失败日志里有 TLS 握手,有重试,有警告,看起来全都可疑。要知道这些可疑之处是否真的是原因,就必须看成功请求的日志里是否也有同样的东西。如果成功里也有,它就不是原因,而是背景。
这套流程是有名字的。它来自医学,叫鉴别诊断(differential diagnosis),在软件领域中也常称为差异诊断。核心只有一点——只看一边,什么都像原因候选;两边都看,大部分会自行被排除。
工作原理
流程分四步。
1. 收集样本。只收集二十个失败样本没有意义。成功样本也要收集差不多的数量。这时,成功样本越是与失败条件最接近的成功越好。来自完全不同国家、不同版本的成功样本,能排除掉的东西很少。
2. 按属性展开。把每个样本变成“属性 = 值”的列表:地区、客户端版本、编码、认证方式、设备、端点、时间段。确定这个列表,实际上是最难的一步——不在列表中的属性,永远不会成为候选。
3. 做两个集合的减法。从所有失败中都有的值的集合中,减去哪怕只在一个成功中出现过的值的集合。剩下的就是候选。这里被排除的值很重要。“所有失败中都有 token 认证”这个事实,一旦与“成功样本中也有三分之一是 token 认证”这个事实放在一起,就什么也说明不了了。
4. 如果候选有两个以上,就把它们分开。这是这套流程真正的难点。
相关不等于原因。如果在同一时期部署的两件事总是同时出现,仅凭样本无法区分它们。表格对二者指向完全相同,并不是因为表格错了,而是因为数据中没有能把二者分开的案例。分开的方法只有两种。
- 获取更多数据。只要出现一个能把二者分开的组合,其中一个就会被排除。在新样本中寻找“有 A 却成功”的案例,或者“没有 B 却失败”的案例。
- 干预。只改变一个属性,固定其余属性,看结果是否翻转。这就是观察与实验的区别,只有实验才能谈因果。
也有无法用单个属性区分的情况。如果只有在编码为 utf-8-sig 且设备为 kiosk 时才会失败,就一个单独的候选也不会留下。因为各自在成功样本中也存在。这时要把值的配对作为候选,再做一次同样的减法。如果继续去看三个及以上的组合,情形数会迅速增加,所以通常看到配对为止,之后用干预来确认。
从数字上看,这套流程为什么有价值就很清楚了。假设有 240 条样本,七个属性,大约二十种值。求 40 条失败的交集,通常会剩下两三个值,再从中减去 200 条成功的并集,就只剩一两个。用眼睛扫一遍,二十个全都可疑,而两次减法,候选就只剩一两个。并不是人变聪明了,而是成功样本替我们排除了其余的。
还有一点。这套流程属性越多越强。记录中没有的属性不可能成为候选,所以在调查初期决定“要一并记录什么”,实际上占了调查的一半。请求头、客户端版本、租户、路径、认证方式,在大多数事件中都有用。
在现场相遇的样子
第一,只收集失败样本。客户只会把失败的发给你,因为成功的没有人保留。所以第一个请求总应该是“成功的也请发同样数量”。
第二,样本有偏。如果失败全都从夜间批处理中收集,成功全都从白天的界面中收集,时间段和路径就会全部作为候选保留下来。收集数据的方式在数据上留下了规律。
第三,只找到一个候选就停下。候选剩下两个时,挑其中看起来更像的一个去报告,有一半的概率会错。而且这样的报告会让修复白白花掉好几天。候选有两个,就写两个,并设计能把它们分开的实验,这才是对的。
第四,不记录被排除的东西。“auth_mode 不是原因”这个事实,能让下一个人不再走同样的路。报告中不仅要写剩下的候选,还要一并写下被排除的候选和排除的依据。
实际工作中真正重要的事
- 成功样本占一半。没有对照组的调查只是猜测。
- 属性列表中没有,就没有候选。先决定要记录什么。
- 如果有两个完全相关的候选,就获取更多数据或进行干预。不要挑看起来更像的那个。
- 单独区分不开,就看配对。交互作用在单独检查中会整个消失。
下一项实验要做什么
用支付网关的 240 条样本制作按属性划分的差异表,挑出存在于所有失败中、且不存在于任何成功中的值。在剩下两个候选的地方,再加入 120 条新样本排除其中一个,并用复现器只改变一个属性,确认结果是否翻转。最后,在另一个无法用单个属性区分的租户样本中找出配对候选,汇总成一页纸进行报告。