使用 wrk 压测并精细控制并发请求量

2021-05-10 16:32:42 浏览数 (2)

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

wrk 的参数

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

代码语言:javascript复制
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 稳定后再继续增加.

代码语言:javascript复制
-- ./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 的数据, 机器的配置如下:

代码语言:javascript复制
内核版本: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

代码语言:javascript复制
@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 再好一点的话, 我觉得并发量可以更高.

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

脚注

[1]

使用 wrk 完成简单的自定义动态请求: https://corvo.myseu.cn/2018/11/15/2018-11-14-wrk动态请求/

原文链接:https://corvo.myseu.cn/2021/03/24/2021-03-24-使用wrk压测并精细控制并发请求量/

0 人点赞