平均值察觉不到尾部在变坏
一句话总结
即使看了同样的日志,但只看平均值的团队决定回溯,只看中位数的团队作为成功案例发表,只看p99的团队启动事件。三者都看了同样的数据。
为什么需要这个?
让我们看看10,000个请求中9,900个是50ms,100个是3,000ms的服务。平均值是79.5ms。实际上,没有一个请求收到79.5ms的响应。平均值描述了不存在的用户。p50、p95、p99都是50ms,只有p99.9是3,000ms。
更糟糕的是灵敏度。即使慢的100个下降到3000→6000ms,两倍那么差,平均也只移动79.5→109.5ms。平均几乎无法感知尾巴变差。
实际部署前后看数字的话,结论分歧的原因就变得很明显了。平均112 → 122ms(+9%),p50 99 → 54ms(−46%),p95 224 → 454ms(+103%),p99 309 → 678ms(+119%)。仅看平均值的话,略有恶化,仅看中位数的话,大改善,看p95/p99的话,严重回归。
怎么行动
如果把p99理解为“1%的不幸用户”,那么就错了优先顺序。尾巴就会放大。请求n次时,至少有一次遇到p99区间的概率是1 − 0.99^n是。
| 呼叫次数 | 遇到p99的概率 |
|---|---|
| 1次 | 1.0% |
| 5次 | 4.9% |
| 20次 | 18.2% |
| 50次 | 39.5% |
| 200次 | 86.6% |
如果一个仪表板的画面调用20个API,那么打开画面一次时遇到p99延迟的概率是18%。如果是每天请求200次的活动用户,87%的人每天都会经历一次以上最坏区间。p99不是少数不幸的用户,而是几乎所有用户的日常。所以如果一个画面调用20个API,服务的一个目标不应该是99%,而是99.9%,在画面水平上98%。
百分位数也不能相加。服务器A(9,900件全部50ms)的p99是50,服务器B(100件全部3,000ms)的p99是3,000。简单的平均值是1,525ms,请求次数加权平均值是79.5ms,真正的综合p99是3,000ms。这三个数字都是不同的,前两个没有任何意义。
在现场相遇的样子
负载测试报告中最常出现的缺陷是没有条件。只有写着RPS和p95,没有同时性、总请求次数、什么时候执行。那种数字不能在下个月进行比较,所以不是基准线。
第二个是只重测一次。在相同条件下旋转三次就会看到波动幅度,比波动幅度小的差异不能称为改善。
正确保存百分位的方法
不能合并p99的问题,如果改变存储方式,大部分都会消失。关键不是百分位数值,而是存储分布。直方图会包含每个桶的记录数,比如“0–10ms有几件,10–25ms有几件”,所以只要加几个实例的桶,就会得到整个分布。从合并后的分布中计算百分位数,那就是真实值。时间轴也是一样的,如果再加一天的5分钟单位直方图,就会得到当天的p99。
相反,直方图中存在固有的误差。只能知道百分位在哪个桶中,其内的准确位置通过插值来估计。因此,将桶边界靠近目标值决定了准确性。如果目标是300ms,边界是100ms后1秒,那么之间所有的值都聚集在一个格子里,无法判断p99。相反,即使把没有人看的10秒上方放在那里也没有损失。
而且最大值无法通过直方图获得。最后一个桶是像“1秒以上”一样打开的,所以无法区分里面有1.1秒还是30秒。在最慢的请求是多少的重要调查中,最大值需要单独作为指标输出,或者需要在日志和跟踪中寻找慢请求本身。
测量什么比数字更重要
即使正确读取百分位数,如果本来是在错误的条件下测量的数字,也毫无用处。负荷测试与现实不符的位置通常已经确定。
不进行热身。 JIT编译、连接池填充、缓存预热,以及自动扩展到响应的时间。开始后30秒不是正常状态,所以如果将该段纳入统计,p99的值会比实际值差得多。相反,即使热身时间过长也是问题。实际用户在发布后也会发送请求,所以需要单独重新了解该段的性能。
数据太干净了。如果所有请求都查询同一个用户、同一个商品,那么第一个请求之后全部从缓存中取出。处理量数字很漂亮,但实际上是不存在的值。相反,如果每次都使用完全随机的密钥,缓存命中率就会变成0,过于悲观。实际访问分布通常集中在少数项目上,所以要模仿那种偏重。
只攻击一个地方。如果将负载集中在一个端点上,就会只看到该路线的瓶颈。在现实中,多个功能共享相同的数据库和相同的线程池,所以一个人本来还不错,但一起运行时就会崩溃。场景应该按照实际流量比例混合。
负载工具首先会耗尽。如果客户端CPU饱和或端口耗尽,不是服务器而是工具的限制。此时出现的延迟增加不是服务器性质。为了避免这种误解,也需要记录负载工具使用的设备资源。
最后,最好也确定留下结果的形式。负载、持续时间、总请求数、错误率、p50/p95/p99,以及当时服务器的CPU、内存、连接数。如果没有这个组合,即使下个月再做同样的考试也无法比较,无法比较的数字不是基准线,只是当天的记录。
下次实验要做的事情
将nginx容器作为负载对象,用hey分开执行烟雾·热身·本测量。在工具输出中,直接提取RPS和p50/p95/p99和错误率,整理成JSON,计算与平均值相比的p95倍数,然后重复三次,确定包括波动幅度在内的基准线。