手把手让你学会从压测到指标分析
介绍
wrk
是一种使用 Lua 编写的 HTTP 压力测试工具,它是一个轻量级的开源工具,适用于测试 Web 服务器和 Web 应用程序的性能。以下是对 wrk
工具的特点、易用性、文档和社区支持等因素的简要介绍:
特点:
- 高性能:
wrk
使用多线程和事件驱动的 I/O 模型,可以获得很高的吞吐量。 - 灵活性:
wrk
具有丰富的选项和配置参数,可用于模拟不同类型的负载和场景。 - 扩展性:
wrk
可以通过编写 Lua 脚本来自定义请求和响应处理逻辑,并可以通过第三方插件扩展其功能。 - 易用性:
wrk
提供了简单的命令行界面,并提供了详细的文档和教程,使其易于学习和使用。
易用性:
wrk
的命令行界面非常简单,几乎不需要学习曲线,同时提供了丰富的选项和配置参数,方便用户进行灵活设置。wrk
的文档和教程相对较多,其中包括官方文档和社区文档,以及一些基于wrk
的案例和应用实践。
文档和社区支持:
wrk
官方文档详尽,包括该工具的安装、配置、使用和测试结果等方面,同时提供了多个示例和用法说明。wrk
的开源代码托管在 GitHub 上,有大量的开发者和用户参与讨论和贡献。wrk
的用户社区较为活跃,其中包括 Stack Overflow 等技术问答平台、GitHub Issues 和 Google Groups 等交流平台。
总之,wrk
是一种轻量级、高性能、灵活可扩展的 HTTP 压力测试工具,易于学习和使用,并且有广泛的文档和社区支持。如果您需要测试 Web 应用程序的性能或进行负载测试,wrk
是一个非常不错的选择。
安装wrk
-
在CentOS上安装Lua:
sudo yum install lua-devel
-
下载
wrk
源代码:rubysudo wget https://github.com/wg/wrk/archive/4.1.0.tar.gz
-
解压缩
wrk
源代码:sudo tar -xvf 4.1.0.tar.gz
-
进入解压后的目录并编译
wrk
:bashcd wrk-4.1.0 && make
-
将
wrk
二进制文件添加到系统PATH中:bashsudo cp wrk /usr/local/bin/
使用wrk
通过以下命令启动wrk
:
xml
wrk -t<number of threads> -c<number of connections> -d<duration> <url>
参数说明:
-t
:线程数。
-t
参数用于指定wrk
创建的线程数量。每个线程将独立地向目标服务器发送请求,从而提高请求的并发性能。线程数应该根据你的 CPU 核心数和测试目标进行调整。通常情况下,线程数应设置为 CPU 核心数或稍微多一些,以达到最佳性能。例如:
-t 4
表示使用 4 个线程进行压力测试。
-c
:连接数。
-c
参数用于指定wrk
与目标服务器建立的并发连接数。连接数越多,生成的并发请求越多,测试服务器的负载越大。连接数应根据服务器的承受能力和测试目标进行调整。请注意,过高的连接数可能导致服务器性能下降,甚至崩溃。例如:
-c 100
表示创建 100 个并发连接进行压力测试。
-d
:测试时长。
-d
参数用于指定压力测试的持续时间。可以使用时间单位(如 s、m、h)来表示秒、分钟和小时。在指定的时间内,wrk
将持续向目标服务器发送请求,并在测试结束后报告性能指标。例如:
-d 30s
表示进行 30 秒的压力测试。
<url>
:要测试的URL。
例如,如果要对http://localhost:8080
进行基准测试,使用以下命令:
arduino
wrk -t4 -c100 -d30s http://localhost:8080
这将创建4个线程和100个连接,在30秒内测试http://localhost:8080
的性能。
wrk
还提供了许多其他选项,如更改HTTP请求头和方法、执行不同的测试场景等。您可以使用以下命令查看所有选项:
bash
wrk --help
高级用法
wrk
是一款基于 Lua 语言的高性能 HTTP 压测工具,可用于测试 Web 应用程序、Web 服务器等的性能指标。除了基本的使用方法外,wrk
还提供了一些高级功能,例如:
- 使用 Lua 脚本进行自定义测试
可以通过编写 Lua 脚本来实现更加灵活和复杂的测试场景。例如,可以自定义请求头、请求体、Cookie、响应处理逻辑等,从而模拟真实的业务场景。
ini
- example.lua
wrk.method = "POST"
wrk.body = '{"name": "test"}'
wrk.headers["Content-Type"] = "application/json"
执行自定义脚本:
shell
$ wrk -s example.lua http://localhost:8080/api/users
- 多线程压测
可以通过 -t
参数指定多少个线程并发执行测试。例如,如果需要使用 4 个线程并发执行测试,则可以使用以下命令:
shell
$ wrk -t4 -c100 -d10s http://localhost:8080/index.html
该命令将启动 4 个线程并发执行测试,每个线程使用 100 个连接数,持续时间为 10 秒。
- 限制请求速率
可以通过 -R
参数来限制每秒钟发送请求的数量。例如,如果需要限制每秒钟发送 500 个请求,则可以使用以下命令:
shell
$ wrk -t4 -c100 -d10s -R500 http://localhost:8080/index.html
该命令将启动 4 个线程并发执行测试,每个线程使用 100 个连接数,持续时间为 10 秒,并且限制每秒钟发送 500 个请求。
- 指定请求头
可以通过 -H
参数来指定请求头。例如,如果需要在请求头中添加 Authorization
字段,则可以使用以下命令:
shell
$ wrk -t4 -c100 -d10s -H "Authorization: Bearer xxx" http://localhost:8080/index.html
该命令将启动 4 个线程并发执行测试,每个线程使用 100 个连接数,持续时间为 10 秒,并且在请求头中添加了 Authorization: Bearer xxx
字段。
- 指定请求方式
可以通过 -m
参数来指定请求方式。例如,如果需要使用 POST
请求方式,则可以使用以下命令:
shell
$ wrk -t4 -c100 -d10s -m POST -s example.lua http://localhost:8080/api/users
该命令将启动 4 个线程并发执行测试,每个线程使用 100 个连接数,持续时间为 10 秒,并且使用 POST
请求方式。
- 输出统计信息
可以使用 -s
参数指定输出格式和内容。例如,如果需要输出每个请求的响应时间分布情况,则可以使用以下命令:
shell
$ wrk -t4 -c100 -d10s -s /usr/share/wrk/scripts/histogram.lua http://localhost:8080/index.html
该命令将启动 4 个线程并发执行测试,每个线程使用 100 个连接数,持续时间为 10 秒,并输出每个请求的响应时间分布情况。
以上是 wrk
的一些高级用法,可以根据具体需求选择相应的参数和选项。
简单Lua 脚本
wrk
命令可以使用 Lua 脚本来扩展其功能。当您需要自定义请求头、请求体或其他高级设置时,编写一个 Lua 脚本是非常有用的。
以下是一个简单的 Lua 脚本示例:
lua
-- 指定 HTTP 请求方法为 GET,URL 为 http://example.com/api
wrk.method = "GET"
wrk.url = "http://example.com/api"
-- 设置请求头,这里添加了一个自定义的 User-Agent 头
wrk.headers["User-Agent"] = "my-wrk-client"
-- 设置请求参数,这里指定了一个 name 参数
wrk.query["name"] = "John"
-- 设置请求体,这里传递了一个 JSON 格式的请求体
wrk.body = '{"key1":"value1","key2":"value2"}'
wrk.headers["Content-Type"] = "application/json"
-- 在发送请求前打印一些信息
function wrk.before_request()
print("sending request to " .. wrk.url)
end
-- 在接收响应后打印一些信息
function wrk.after_response(status, headers, body)
print("received response: " .. status)
end
在上面的例子中,我们首先指定了 HTTP 请求方法为 GET,并将 URL 设置为 http://example.com/api
。然后,我们设置了一个自定义的 User-Agent 请求头和一个名为 name
的查询参数。
接下来,我们设置了一个 JSON 格式的请求体,并将 Content-Type 设置为 application/json。
在发送请求前和接收响应后,我们分别使用 wrk.before_request()
和 wrk.after_response()
函数来打印一些信息。
请注意,您需要根据自己的需求修改这个 Lua 脚本中的参数和函数,并使用 wrk -s
命令指定该脚本来发送 HTTP 请求。例如:
perl
$ wrk -t2 -c100 -d30s -s my-script.lua http://example.com/api
复杂Lua脚本
当您需要在 wrk
场景中传递复杂的参数,例如同时指定 URL、请求头和请求体时,可以编写一个 Lua 脚本来实现。以下是一个示例 Lua 脚本,它演示了如何在 wrk
中发送包含 URL、请求头和请求体的 HTTP POST 请求:
lua
-- 设置请求方法为 POST 和请求 URL
wrk.method = "POST"
wrk.headers["Content-Type"] = "application/json"
wrk.url = "http://example.com/api?name=John&age=30"
-- 设置请求头
wrk.headers["Authorization"] = "Bearer <token>"
-- 设置请求体
wrk.body = '{"key1":"value1","key2":"value2"}'
-- 在发送请求前打印一些信息
function wrk.before_request()
print("sending request to " .. wrk.url)
end
-- 在接收响应后打印一些信息
function wrk.after_response(status, headers, body)
print("received response: " .. status)
end
在上面的脚本中,我们首先设置了 HTTP 请求方法为 POST,并将 URL 设置为 http://example.com/api?name=John&age=30
。然后,我们设置了一个 Authorization 请求头。
接下来,我们设置了一个 JSON 格式的请求体。最后,在发送请求前和接收响应后,我们分别使用 wrk.before_request()
和 wrk.after_response()
函数来打印一些信息。
请注意,您需要根据自己的需求修改这个 Lua 脚本中的参数和函数,并使用 wrk -s
命令指定该脚本来发送 HTTP 请求。例如
perl
$ wrk -t2 -c100 -d30s -s my-script.lua http://example.com/api
在上面的命令中,我们使用 -s
选项指定了 my-script.lua
文件的路径,并将其作为最后一个参数传递给 wrk
命令。 wrk
将读取该文件并使用其中的配置来发送 HTTP POST 请求,其中包含了 URL、请求头和请求体。
含义
bash
Running 30s test @ http://127.0.0.1:8080/hello/aaaaaaa
4 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.73ms 1.31ms 24.49ms 92.07%
Req/Sec 1.22k 171.29 1.78k 69.75%
146540 requests in 30.09s, 34.96MB read
Requests/sec: 4870.51
Transfer/sec: 1.16MB
wrk
是一个用于测试 HTTP 服务的负载的现代工具。它会创建指定数量的线程,打开多个 TCP 连接,并向指定的 URL 发送 HTTP 请求,以此来测试服务器的处理能力。
以下是关于这个 wrk
测试结果的解释:
-
Running 30s test @ http://127.0.0.1:8080/hello/aaaaaaa
: 这是在运行一个针对http://127.0.0.1:8080/hello/aaaaaaa
的 30 秒的测试。 -
4 threads and 10 connections
: 这表示测试使用了 4 个线程,每个线程维持了 10 个连接。 -
Thread Stats
: 这是关于每个线程的统计信息。Latency
: 这是响应延迟的统计信息。平均延迟是 1.73 毫秒,标准偏差是 1.31 毫秒,最大延迟是 24.49 毫秒,92.07% 的延迟在平均延迟的一个标准偏差内。Req/Sec
: 这是每秒请求的统计信息。平均每秒请求 1.22k,标准偏差是 171.29,最大每秒请求 1.78k,69.75% 的每秒请求在平均每秒请求的一个标准偏差内。
-
146540 requests in 30.09s, 34.96MB read
: 在 30.09 秒内,发送了 146540 个请求,并且读取了 34.96 MB 的数据。 -
Requests/sec: 4870.51
: 这是每秒请求的平均值,即在整个测试期间,平均每秒有 4870.51 个请求。 -
Transfer/sec: 1.16MB
: 这是每秒传输的平均数据量,即在整个测试期间,平均每秒传输了 1.16 MB 的数据。
这些指标是否合适,往往取决于你的应用的需求和预期。以下是一些你可以考虑的因素:
- 延迟(Latency) :这个指标衡量的是服务器从接收请求到发送响应所需的时间。低延迟通常意味着更好的用户体验,因为用户可以更快地得到他们请求的信息。如果你的应用需要快速响应(例如,实时聊天应用或游戏),你可能需要将延迟降低到最小。你的平均延迟是1.73ms,这个数值对于大多数应用来说是非常快的。
- 每秒请求数(Requests/sec) :这个指标衡量的是服务器每秒能处理多少个请求。如果你的应用需要处理大量的并发请求,你需要一个高的每秒请求数。你的平均每秒请求数是4870.51,这个数值对于中小型应用来说是很好的。
- 数据传输速率(Transfer/sec) :这个指标衡量的是服务器每秒能发送多少数据。如果你的应用需要传输大量的数据(例如,流媒体服务或文件共享服务),你需要一个高的数据传输速率。你的平均每秒传输速率是1.16MB,这个数值取决于你的应用需求可能会有所不同。
总的来说,这些指标的好坏取决于你的应用需求。如果你的应用在当前的性能下可以满足用户的需求并提供良好的用户体验,那么这些指标就是合适的。但是,如果你的应用在高负载下表现不佳,或者用户反馈响应慢,那么你可能需要进一步优化你的应用或服务器配置。
对于机器的影响,我们通常会考虑以下几个关键指标:
- CPU 使用率:这是一个重要的指标,它衡量了你的应用对服务器 CPU 的需求。如果 CPU 使用率非常高(例如,接近或者达到 100%),那么你的应用可能会因为 CPU 资源不足而性能受限。在这种情况下,你可能需要优化你的应用以减少 CPU 使用,或者升级你的服务器以提供更多的 CPU 资源。
- 内存使用:这是另一个重要的指标,它衡量了你的应用对服务器内存的需求。如果内存使用非常高,那么你的应用可能会因为内存资源不足而性能受限。在这种情况下,你可能需要优化你的应用以减少内存使用,或者升级你的服务器以提供更多的内存资源。
- 磁盘 I/O:如果你的应用需要频繁地读写磁盘,那么磁盘 I/O 可能会成为一个性能瓶颈。你可以通过监视磁盘 I/O 操作的数量和速度来评估你的应用对磁盘性能的需求。
- 网络使用:如果你的应用需要大量的网络传输,那么网络带宽可能会成为一个限制因素。你可以通过监视网络传输速率和网络延迟来评估你的应用对网络性能的需求。
你可以使用各种系统监控工具(如 top
,vmstat
,iostat
,netstat
等)来监视这些指标。此外,还有一些更高级的监控解决方案(如 Prometheus,Grafana,New Relic 等)可以提供更详细和更丰富的性能数据。
在处理并发请求时,连接数和线程数是两个关键概念:
- 连接数:这指的是同时连接到服务器的客户端数量。每个客户端(例如,浏览器或其他类型的客户端应用)在请求服务器资源时会创建一个或多个连接。
- 线程数:这是服务器用来处理并发请求的线程数量。当一个请求到达服务器时,服务器会分配一个线程来处理这个请求。
如果你的系统需要处理大量并发请求,那么你需要有足够的线程和连接来处理这些请求。如果你的线程数或连接数不足,那么一部分请求将被迫等待,这会导致延迟增加和性能下降。
判断是否需要扩充机器,你需要考虑以下几个关键因素:
- CPU 和内存使用:如果你的服务器的 CPU 或内存使用率过高,那么你可能需要增加更多的服务器资源。高的 CPU 或内存使用率通常意味着服务器资源已经饱和,无法处理更多的请求。
- 延迟和错误率:如果你的系统的延迟增加或错误率上升,那么这可能是一个信号,表明你的系统正在超过其处理能力的极限。
- 负载均衡:如果你的系统使用了多个服务器,并且某些服务器的负载明显高于其他服务器,那么你可能需要更好地分配你的负载,或者增加更多的服务器。
- 业务增长预测:如果你预计你的业务在未来会有显著增长,那么你可能需要预先扩充你的服务器资源,以应对这种增长。
你可以使用各种性能监控工具来帮助你做出这些判断,例如 New Relic,Datadog,Prometheus,Grafana 等。这些工具可以提供实时的性能数据,并帮助你识别系统的瓶颈和问题。
模拟 1000 个用户同时访问的情况,你需要考虑几个关键因素,包括你的应用程序的性质、你的服务器配置以及你的网络环境。
线程数:线程数基本上是你的服务器可以并行处理的请求的数量。如果你的服务器是多核的,那么你可以配置比你的核心数更多的线程,这样可以更好地利用多核的优势,因为在任何时刻,一个核心可以执行一个线程的代码。然而,如果线程数设置得过高,可能会引发上下文切换过多,反而导致性能下降。
连接数:连接数是服务器可以处理的并发连接的数量。如果你有 1000 个用户,每个用户只打开一个连接,那么你需要至少 1000 个并发连接。但是,实际的连接数可能需要更高,因为在高并发的情况下,有些连接可能在等待处理,而其他的连接可能在处理请求。所以,你需要有足够的连接数来处理这些等待的连接。
至于具体的数值,这很大程度上取决于你的应用的需求和你的服务器的能力。一般来说,线程数和连接数不应该设置得过高,否则可能会导致服务器资源过载。你可以通过性能测试和监控来调整这些设置,以找到最优的配置。
同时,你可以使用压力测试工具(如 JMeter、Locust 或 Gatling)来模拟大量用户并发访问的场景,这样可以更好地理解你的应用在高并发情况下的行为,从而做出合理的线程和连接配置。
说明
压力测试的主要关注点通常包括以下几个方面:
- 吞吐量(Throughput) :这是指系统在单位时间内处理的请求数量,它可以帮助你了解系统在高负载下能处理多少请求。
- 延迟(Latency) :这是指系统响应请求的时间,通常以毫秒为单位。延迟越低,用户体验越好。
- 错误率(Error Rate) :这是指在请求过程中出错的请求比例。一个健康的系统应该尽可能地保持低错误率。
- 并发用户数(Concurrency) :这是指在同一时间内请求系统的用户数量。
这些指标可以帮助你了解你的系统在不同的负载下的表现。
要将这些指标与具体的场景和用户数量关联起来,你需要理解你的业务需求和用户行为。例如,如果你的系统是一个电商网站,并且你预计在黑五购物节当天会有大量用户访问,那么你可能需要进行压力测试,模拟这种高并发的场景,看看你的系统是否能处理这种负载。
在设置压力测试的参数时,你需要考虑到:
- 并发用户数:这应该反映你预计的最大用户数量。例如,如果你预计你的系统在高峰时期可能有 1000 个并发用户,那么你的压力测试应该模拟这个数量。
- 请求速率:这应该反映你预计的用户行为。例如,如果你的用户平均每分钟发送 10 个请求,那么你的压力测试应该模拟这个请求速率。