在之前的文章使用wrk完成简单的自定义动态请求, 我介绍了如何使用wrk制造随机请求, 也给出了lua脚本的使用方式, 这篇博客主要想介绍下在压测时如何利用wrk精细控制并发请求.

wrk的参数

wrk中并没有qps控制的选项, 它只能控制连接数目, 指定的连接数会平均分配到每个线程

1
2
3
4
5
6
7
8
9
10
11
Usage: wrk <options> <url>                            
Options:
-c, --connections <N> Connections to keep open
-d, --duration <T> Duration of test
-t, --threads <N> Number of threads to use

-s, --script <S> Load Lua script file
-H, --header <H> Add header to request
--latency Print latency statistics
--timeout <T> Socket/request timeout
-v, --version Print version details

例如./wrk -t8 -c1000

就是启动8个线程, 每个线程维持125个连接

连接数与并发数关系

1s内可以处理的请求数目被称为qps.

考虑这样一个问题, 假如你想拥有1000qps的效果, 而你的处理能力是0.2s一个请求, 假设服务器足够多, 那么在这1s内,怎么能拥有1000次请求?

可以将1s分成5份(0.2s), 然后1000个请求在5份中平均的发生, 每一份就有200个请求, 因此我们需要200个并发连接.

实践

这是大约估计的方案, 实际使用中, 可能需要注意一点, 如果你的请求响应本身就很快, 比如0.05s, 那么可能并发估计没有那么准, 主要是因为请求链路上可能会有其他时间消耗, 如果我们使用200的并发连接, 200/0.05理论是应该有4000的qps, 但是其他耗时导致并发低于4000是很正常的.

我在使用wrk的时候, 并不是直接把请求数目增加到很高, 因为我们平时不一定有足量的后端机器, 一次性增加大量请求可能会导致服务可用性下降, 可以逐步增加请求数, 我是这么做的, 指定压测内容的响应时间0.1s, 再指定并发连接数, 使用时, 多跑几次脚本, 看到qps稳定后再继续增加.

1
2
3
4
5
6
7
8
9
10
11
-- ./wrk -t10 -c400 -d3600s -T2s -s 4k.lua
-- 400个并发请求, 可以达到4k的qps
request = function()
local path = "/test/wait"
local body = "wait=0.1"

local headers = {}
headers["Content-Type"] = "application/x-www-form-urlencoded"
headers["Host"] = "XXX"
return wrk.format('GET', path, headers, body)
end

比如现在, qps已经稳定

响应时间也比较稳定

可能大家不太懂P50是什么意思, 最下面绿色的线表示 50%以上的请求都能在0.2s以内完成,

这样会得到稳定请求状态下的数据

总结

希望读者能了解wrk参数的设置, 以及表现到Nginx中实际的效果, 可能有一天你压测的时候就能用到了.

附录 – 我对于Ingress的压测过程

近期压测Ingress主要是因为有个大应用会接入到我们的系统中, 可能比原有所有应用的流量加起来都要多, 不压测的话, 用户使用的信心没有那么足.

压测脚本就是用的上面0.1s的数据, 机器的配置如下:

1
2
3
4
5
6
内核版本: 4.9.0-15-amd64
操作系统: Debian 9.13
内存大小: 131072 M
CPU 核数: 24
CPU 个数: 2
CPU: Intel(R) Xeon(R) Silver 4214R CPU @ 2.40GHz

后台uwsgi程序

每个pod使用40个worker, 开启了gevent, CPU限制10个核(测试中利用率不到5个), pod数目在压测时尽量保证够用, 有15个

请求的接口如下, 压测时统一了等待时间为0.1s

1
2
3
4
5
6
7
8
9
10
11
@index_handler.route('/test/wait', methods=['POST', 'GET'])
@response_process
def test_wait():
wait = float(request.values.get('wait', 5))
import gevent
gevent.sleep(wait)
result = {
'status': 'ok',
'wait': wait,
}
return jsonify(result=result)

多种qps下, Ingress的具体表现

我针对Kubernetes的Ingress机器进行了一次压力测试, 主要测试各个请求量下, Ingress的各项指标 测试时间: 11:30~12:00

并发数量 cpu利用率 mem利用 应用响应情况
0 20% 2.4G 无请求
3.6k 160% 2.3G 程序响应时间稳定
7.1k 291% 2.35G 程序响应时间稳定
10.4k 413% 3.36 程序响应基本稳定
11.8k 470 2.37G 程序响应已经变慢, P50-180ms P90 244ms P99 470ms ,加了机器也没有提升

在达到uwsgi瓶颈之后, 我开始增加对于静态资源的请求, 尝试更大的并发

并发数量 cpu利用率 mem利用 应用响应情况
13.2K 490 % 2.4G 请求静态资源, 响应正常

这个程序在达到13~14k之后已经到了瓶颈, 这个时候, 我只能保留这个程序的请求量, 加入另一个程序用于压测.

另一个程序, 我没有再指定wait的等待时间, 希望这个程序可以尽可能快的返回, 让我得到尽可能高的并发.

并发请求时, 新应用的qps在25k左右,

此时的Ingress开始接近性能瓶颈,可以看到请求峰值时, cpu利用率在下降

此次压测结论

14kqps(第一个应用) + 25k(第二个应用) 单机的Ingress的大概能允许40K左右的并发, 达到这个阶段后, 主要瓶颈是在CPU. 如果CPU再好一点的话, 我觉得并发量可以更高.

如果觉得我压测方法不科学或者有其他想讲的, 可以在评论里面说, 我看看是不是过程有问题.