怎么模拟延迟、错误、断连和进程被杀?各种故障在 client 眼里是什么样子?随机杀实例时,重试和摘除各能挡住多少?这篇用自己写的 TCP 代理、应用层注入和真的 kill -9 做三层故障注入。
模式 | client 看到的结果 | 延迟中位数
------------------+---------------+---------
直连(不经过代理) | {'200': 20} | 1 ms
代理透传 | {'200': 20} | 1 ms
延迟:每个数据块先等 100 ms | {'200': 20} | 208 ms
重置:一连上就发 RST | {'连接被重置': 20} | 0 ms
黑洞:收下请求但不转发、不回复 | {'超时': 20} | 2003 ms
限速:响应 100 KB/s | {'200': 20} | 239 ms
切碎:每个字节单独发一次 | {'200': 3} | 14191 ms
限速和切碎都没有触发 2 s 的超时:socket 超时是“两次收到数据之间最多等多久”,只要对端还在一点一点地发,总耗时可以远远超过超时(切碎时一个请求要十几秒)延迟、重置、黑洞、限速、切碎在 client 看来各是不同的症状;限速和切碎不会触发 socket 超时。
client 策略 | 最终成功 | 延迟中位数 | p99 | 平均每个请求发了几次 ------------------+-------+-------+--------+----------- 不重试,超时 1 s | 75.5% | 8 ms | 311 ms | 1.00 超时 100 ms,最多试 3 次 | 94.2% | 8 ms | 215 ms | 1.62
错误加慢响应下,短超时加重试能把成功率和 p99 都拉好,代价是多发请求。
client 策略 | 请求失败率 | 成功请求延迟中位数 | p99 | 平均每个请求发了几次 | kill -9 的次数 ------------------------+-------+-----------+-------+------------+------------ (a) 只连固定的一个副本 | 9.8% | 8 ms | 10 ms | 1.00 | 8 (b) 轮询,不重试 | 12.2% | 8 ms | 10 ms | 1.00 | 8 (c) 轮询 + 失败换副本重试 | 0.0% | 8 ms | 11 ms | 1.18 | 8 (d) (c) + 失败的副本 1 秒内不再选 | 0.0% | 8 ms | 11 ms | 1.01 | 8 每个副本从被 kill 到重新拉起约有 0.6 s 不可用,约每 1.5 秒一轮;(a) 和 (b) 失败率的期望相同(都是一个副本不可用的时间占比,约 8 次 × 0.6 s ÷ 3 ÷ 12 s ≈ 13%),区别只是 (a) 取决于被杀的恰好是不是它;重试加换副本能把用户可见的失败压到接近 0,摘除让每个请求少白发几次
重试加换副本把用户可见的失败压到 0,摘除让白发的请求更少。