TT Lab
开始
学习 学习路径 课程

压力测试

压测的目标数值从哪里来

在 TT Lab 中继续学习

目标

从 4 周的按小时流量数据出发,依次应用日总量、峰值时段、安全系数、故障余量和增长率,推导出压力测试的目标 RPS,并进一步确认这个目标在本环境中能否真正施加出来。

为什么重要

压力测试计划书中最常空缺的一栏,是目标 RPS 的来源。如果问“每秒 1,000 次”是从哪里来的,通常没有答案,这样即使测试通过,也说不清保证了什么。目标必须从生产数据中推导出来。把一天的总量除以 86400 得到的平均值,几乎总是比实际峰值小好几倍,如果按这个平均值来规划容量,就会恰好少掉这个倍数。再依次乘上:即使在峰值时也不用尽容量的余量(headroom)、即使一个可用区掉线也能承受的冗余,以及到下一个规划周期为止的增长率。最后,还必须确认按此确定的目标是否真的能施加出来——用没能施加出来的负载得到的通过,不是通过。

步骤

  1. /opt/lab/lt/lt-capacity-target/traffic.tsv 是 4 周的按小时请求数(一行表头之后是 날짜 시각 요청수(韩文,依次意为日期、时刻、请求数))。把按日期的合计,以 28 行、每行以制表符分隔的两个字段 <날짜> <하루 총 요청 수>(占位符依次为日期、每日请求总数)写入 /root/lt-capacity-target/daily.tsv,并在 /root/lt-capacity-target/01-peak-day.txt 中写两行 peak_date= 和 peak_total=。也就是最忙的那一天。
  2. 在最忙那一天的 24 小时中,找出最忙的一个小时,在 /root/lt-capacity-target/02-peak-hour.txt 中写三行:peak_hour=(0 到 23 的整数)、peak_hour_requests=(那一个小时的请求数)、peak_share=(那一个小时占当天总量的比例,保留到小数点后第四位)。
  3. 在 /root/lt-capacity-target/03-rps.txt 中写三行。avg_rps= 是最忙那天的总量除以 86400 所得的值,peak_rps= 是最忙一个小时的请求数除以 3600 所得的值(两者都保留到小数点后第二位),peak_over_avg= 是两者之比(保留到小数点后第二位)。
  4. 把运行余量(headroom)定为 30%——意思是即使在峰值时,也只使用容量的 70%。在 /root/lt-capacity-target/04-headroom.txt 中写两行 headroom=0.30 和 rps_after_headroom=。后一个值是 peak_rps ÷ (1 − headroom),保留到小数点后第二位。
  5. 服务均匀部署在 4 个可用区,即使一个可用区整个掉线,也必须承受峰值。在 /root/lt-capacity-target/05-nplus1.txt 中写三行 nodes=4、surviving=3、rps_after_nplus1=。后一个值是 rps_after_headroom × nodes ÷ surviving,保留到小数点后第二位。
  6. 流量每月增长 8%,并且要靠这个容量撑过 6 个月。在 /root/lt-capacity-target/06-growth.txt 中写四行 monthly_growth=0.08、months=6、growth_factor=(1.08 的 6 次方,保留到小数点后第四位)、rps_after_growth=(rps_after_nplus1 × growth_factor,保留到小数点后第二位)。
  7. 创建 /root/lt-capacity-target/target.tsv。没有表头,共五行,每行是以制表符分隔的两个字段 <단계> <RPS>(占位符依次为阶段、RPS)。阶段名称依次为 peak、headroom、nplus1、growth、target,前四行写前面几步写下的值,最后的 target 行写 rps_after_growth 向上取整后的整数。然后在 /root/lt-capacity-target/07-note.txt 中写两行 test_target_rps=(那个整数)和 reason=(用至少 60 个字符写明这个目标是从哪里来的)。
  8. 把 /opt/lab/lt/lt-capacity-target/echo.py 启动在端口 8095 上,并把第 7 步确定的目标真正施加上去。worker 为 20 个,每个 worker 的速率上限是 올림(목표 ÷ 20)(即目标除以 20 后向上取整),请求数是 목표 × 5(即目标乘以 5),并把原始 CSV 保留在 /root/lt-capacity-target/run.csv 中。然后在 /root/lt-capacity-target/08-run.txt 中写五行 target_rps=、workers=20、q_per_worker=、measured_rps=(根据 run.csv 重新计算的值,保留到小数点后第二位)、reached=(如果 measured 达到目标的 90% 以上则为 yes,否则为 no),并加上一行至少 50 个字符的 note=。

参考

先统计一天的总量

/opt/lab/lt/lt-capacity-target/traffic.tsv 是 4 周的按小时请求数(一行表头之后是 날짜 시각 요청수(韩文,依次意为日期、时刻、请求数))。把按日期的合计,以 28 行、每行以制表符分隔的两个字段 <날짜> <하루 총 요청 수>(占位符依次为日期、每日请求总数)写入 /root/lt-capacity-target/daily.tsv,并在 /root/lt-capacity-target/01-peak-day.txt 中写两行 peak_date= 和 peak_total=。也就是最忙的那一天。

用 awk -F'\t' 按日期累加第三个字段即可。请跳过表头那一行。容量规划的基准不是平均值,而是最忙的那一天——如果按平均值来定,那一天就会垮掉。

在这一天之内,什么时候最忙

在最忙那一天的 24 小时中,找出最忙的一个小时,在 /root/lt-capacity-target/02-peak-hour.txt 中写三行:peak_hour=(0 到 23 的整数)、peak_hour_requests=(那一个小时的请求数)、peak_share=(那一个小时占当天总量的比例,保留到小数点后第四位)。

如果 24 小时是均匀的,一个小时的份额是 1 ÷ 24 = 0.0417。这一步的要点是实际值是它的几倍——这个倍数,就是“按平均值规划会少多少”。

除以平均值,会少掉多少倍

在 /root/lt-capacity-target/03-rps.txt 中写三行。avg_rps= 是最忙那天的总量除以 86400 所得的值,peak_rps= 是最忙一个小时的请求数除以 3600 所得的值(两者都保留到小数点后第二位),peak_over_avg= 是两者之比(保留到小数点后第二位)。

一天的总量 ÷ 86400,是“如果那一天 24 小时始终一样忙”的值。实际峰值比它大得多。如果不知道这个倍数,就按平均值来定容量,在峰值时段恰好会少掉这个倍数。

留出余量,抬高目标

把运行余量(headroom)定为 30%——意思是即使在峰值时,也只使用容量的 70%。在 /root/lt-capacity-target/04-headroom.txt 中写两行 headroom=0.30 和 rps_after_headroom=。后一个值是 peak_rps ÷ (1 − headroom),保留到小数点后第二位。

如果在峰值时把容量用到 100%,就已经处在队列开始堆积的那个点上了。在排队论中,利用率越接近 1,等待时间就增长得越急剧。所以目标要定在峰值之上。这是除法——不是乘以 0.7。

让它在一个可用区掉线时也能承受

服务均匀部署在 4 个可用区,即使一个可用区整个掉线,也必须承受峰值。在 /root/lt-capacity-target/05-nplus1.txt 中写三行 nodes=4、surviving=3、rps_after_nplus1=。后一个值是 rps_after_headroom × nodes ÷ surviving,保留到小数点后第二位。

四个可用区只剩 3 个时,为了承受同样的负载,整体必须拥有 4/3 倍的容量。所以测试中需要确认的负载也要相应提高。如果漏掉这个系数,平时没有任何问题,只会在一个可用区掉线的那一天垮掉——这是最糟糕的失败方式。

半年之后这个目标还能用吗

流量每月增长 8%,并且要靠这个容量撑过 6 个月。在 /root/lt-capacity-target/06-growth.txt 中写四行 monthly_growth=0.08、months=6、growth_factor=(1.08 的 6 次方,保留到小数点后第四位)、rps_after_growth=(rps_after_nplus1 × growth_factor,保留到小数点后第二位)。

这是复利——不是 8% × 6 = 48%,而是 1.08 的 6 次方。请亲自算一算两者的差别会让目标数值改变百分之几。增长率原则上应该从数据中估计,但在这一步中,把它当作从产品规划中拿到的值,把注意力集中在计算方法上。

把目标的来源留在一个文件里

创建 /root/lt-capacity-target/target.tsv。没有表头,共五行,每行是以制表符分隔的两个字段 <단계> <RPS>(占位符依次为阶段、RPS)。阶段名称依次为 peak、headroom、nplus1、growth、target,前四行写前面几步写下的值,最后的 target 行写 rps_after_growth 向上取整后的整数。然后在 /root/lt-capacity-target/07-note.txt 中写两行 test_target_rps=(那个整数)和 reason=(用至少 60 个字符写明这个目标是从哪里来的)。

这一张表,就是对“每秒 1,000 次是从哪里来的”这个问题的回答。看这四行,还能一眼看出改变哪个假设,目标会移动多少——请在脑子里算一算,如果把余量降到 20%,目标会变成多少。

这个目标在本环境中究竟能不能施加出来

把 /opt/lab/lt/lt-capacity-target/echo.py 启动在端口 8095 上,并把第 7 步确定的目标真正施加上去。worker 为 20 个,每个 worker 的速率上限是 올림(목표 ÷ 20)(即目标除以 20 后向上取整),请求数是 목표 × 5(即目标乘以 5),并把原始 CSV 保留在 /root/lt-capacity-target/run.csv 中。然后在 /root/lt-capacity-target/08-run.txt 中写五行 target_rps=、workers=20、q_per_worker=、measured_rps=(根据 run.csv 重新计算的值,保留到小数点后第二位)、reached=(如果 measured 达到目标的 90% 以上则为 yes,否则为 no),并加上一行至少 50 个字符的 note=。

总 RPS 是 요청 수 ÷ (max(offset + response-time) − min(offset))(即请求数除以 max(offset + response-time) 与 min(offset) 之差)。如果没能施加出目标,那不是服务器的结论,而是生成器的局限,必须在报告中写明这一点——如果不写,下一个人就会把这个数字当作服务器的能力来读。