专栏首页云计算教程系列如何在Ubuntu 14.04上使用wrk对HTTP延迟进行基准测试
原创

如何在Ubuntu 14.04上使用wrk对HTTP延迟进行基准测试

介绍

本文重点介绍称为开源HTTP基准测试工具WRK,它可以在高负荷下测量HTTP服务的延迟。

延迟是指请求发生的时间(通过wrk)和收到响应的时刻(来自服务)之间的时间间隔。这可用于模拟访问者在使用浏览器或任何其他发送HTTP请求的方法访问网站时在您的网站上遇到的延迟。

wrk对于测试任何依赖HTTP的网站或应用程序非常有用,例如:

  • Rails和其他Ruby应用程序
  • Express和其他JavaScript应用程序
  • PHP应用程序
  • 在Web服务器上运行的静态网站
  • Nginx这样的负载均衡器背后的站点和应用程序
  • 你的缓存层

测试无法真实用户进行比较,但它们应该能够很好地估计预期延迟,以便您可以更好地规划基础架构。测试还可以让您深入了解性能瓶颈。

wrk是开源的,可以在GitHub找到

它非常稳定,并且由于其多线程特性,可以模拟高负载。wrk的最大特点是它能够集成Lua脚本,这增加了许多可能性,例如:

  • 使用cookie对请求进行基准测试
  • 自定义报告
  • 对多个URL进行基准测试 - 也就是现在流行的ab,这个功能也是Apache HTTP服务器基准测试工具所不具备的。

先决条件

我们将在本教程中使用的基础结构如下图所示:

如您所见,我们将在非常简单的场景中使用wrk。我们将在Node.js应用程序上对Express进行基准测试。

我们将启动两个腾讯CVM:一个用于生成负载的wrk,另一个用于应用程序。如果他们在同一个盒子上,他们会竞争资源,我们的结果将不可靠。

基准测试的机器应该足够强大以处理受压系统,但在我们的情况下,应用程序非常简单,我们将使用相同尺寸的机器。

  • 因为它们将通过私有IP进行通信,所以在同一区域中旋转两个腾讯CVM
  • 在本教程中调用一个腾讯CVM wrk1和另一个app1
  • 选择2 GB内存
  • 选择Ubuntu 14.04,没有服务器的同学可以在这里购买,不过我个人更推荐您使用免费的腾讯云开发者实验室进行试验,学会安装后在购买服务器
  • 在“ 可用设置”部分中选择“ 专用网络**”**
  • 在每台服务器上创建一个sudo用户

较小的腾讯CVM也可以工作,但是你应该期望测试结果有更多的延迟。在实际测试环境中,您的应用服务器应与您打算在生产中使用的大小相同。

第1步 - 两个服务器:安装Docker

为了让我们的生活更轻松,我们将使用Docker,因此我们可以在容器内启动wrk和我们的应用程序。这让我们可以跳过设置Node.js环境,npm模块和deb软件包; 我们所需要的只是下载并运行相应的容器。节省的时间将用于学习wrk。

注意:本节中的命令应在两个腾讯CVM上执行。

要安装Docker,请登录到您的服务器并执行以下命令。首先,更新包列表:

sudo apt-get update

安装Wget和cURL:

sudo apt-get install -y wget curl

下载并安装Docker:

sudo wget -qO- https://get.docker.com/ | sh

将您的用户添加到docker组中,这样您就可以在不使用sudo的情况下执行Docker命令:

sudo gpasswd -a ${USER} docker
sudo service docker restart
newgrp docker

如果您使用的是其他Linux发行版,Docker的安装文档可能会涵盖您的案例。

要验证docker是否已正确安装,请使用以下命令:

docker --version

你应该得到以下或类似的输出:

OutputDocker version 1.7.1, build 786b29d

第2步 - 准备测试应用程序

app1腾讯CVM上执行这些命令。

出于测试目的,作者在公共Docker注册表中发布了Docker镜像。它包含一个用Node.js编写的HTTP调试应用程序。它不是一个性能野兽(我们今天不打破任何记录)但它足以进行测试和调试。你可以在这里查看源代码。

当然,在现实生活中,您可能希望测试自己的应用程序。

在我们启动应用程序之前,让我们将腾讯CVM的私有IP地址保存到一个名为APP1_PRIVATE_IP的变量中:

export APP1_PRIVATE_IP=$(sudo ifconfig eth1 | egrep -o "inet addr:[^ ]*" | awk -F ":" '{print $2}')

您可以使用以下方式查看私有IP:

echo $APP1_PRIVATE_IP

输出:

Output
10.135.232.163

您的私人IP地址会有所不同,请注意。

现在只需执行以下命令即可启动应用程序:

docker run -d -p $APP1_PRIVATE_IP:3000:3000 --name=http-debugging-application czerasz/http-debugger

上面的命令将首先下载所需的Docker镜像,然后运行Docker容器。容器以分离模式启动,这意味着它将在后台运行。该选项-p $APP1_PRIVATE_IP:3000:3000将代理3000端口上本地容器和主机私有IP之间的所有通信

现在测试curl以查看应用程序是否正在运行:

curl -i -XPOST http://$APP1_PRIVATE_IP:3000/test -d 'test=true'

预期产量:

Output
HTTP/1.1 200 OK
X-Powered-By: Express
X-Debug: true
Content-Type: text/html; charset=utf-8
Content-Length: 2
ETag: W/"2-79dcdd47"
Date: Wed, 13 May 2015 16:25:37 GMT
Connection: keep-alive
​
ok

该应用程序非常简单,只返回一条ok消息。所以每次wrk请求这个应用程序时,它都会收到一条简短的ok消息。

最重要的部分是我们可以通过分析应用程序日志来查看wrk对我们的应用程序的请求。

使用以下命令查看应用程序日志:

docker logs -f --tail=20 http-debugging-application

您的示例输出应如下所示:

Output
[2015-05-13 16:25:37] Request 1
​
POST/1.1 /test on :::3000
​
Headers:
 - user-agent: curl/7.38.0
 - host: 0.0.0.0:32769
 - accept: */*
 - content-length: 9
 - content-type: application/x-www-form-urlencoded
​
No cookies
​
Body:
test=true

如果您愿意,可以在运行基准测试时保持运行。用CTRL-C退出尾巴。

第3步 - 安装wrk

登录wrk1服务器,准备安装wrk

由于我们有Docker,因此非常容易。只需使用以下命令从Docker注册表中心下载映像williamyeh/wrk

docker pull williamyeh/wrk

上面的命令下载了包含wrk的Docker镜像。我们不需要构建wrk,也不需要安装任何其他软件包。要运行wrk(在容器内),我们只需要根据此图像启动容器就可以完成,这也是我们即将去做的事情。

下载应该只需几秒钟,因为图像非常小 - 小于3 MB。如果您想直接在您喜爱的Linux发行版上安装wrk,请访问此Wiki页面并按照说明操作。

我们还将在此服务器上设置变量APP1_PRIVATE_IP。我们需要来自app1 腾讯CVM 的私有IP地址。

导出变量:

export APP1_PRIVATE_IP=10.135.232.163

请记住将10.135.232.163IP地址更改为app1 腾讯CVM的私有IP。此变量仅保存在当前会话中,因此请记住在下次登录使用wrk时重新设置它。

第4步 - 运行wrk基准测试

在本节中,我们将最终看到wrk的运行。

本节中的所有命令都应该在wrk1腾讯CVM上执行。

让我们看看wrk为我们提供的选项。仅使用--version标志运行wrk容器将打印出关于其用法的简短总结:

docker run --rm williamyeh/wrk --version

输出:

Output
wrk 4.0.0 [epoll] Copyright (C) 2012 Will Glozer
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
​
  Numeric arguments may include a SI unit (1k, 1M, 1G)
  Time arguments may include a time unit (2s, 2m, 2h)

现在我们已经有了一个很好的概述,现在让我们编写命令来运行我们的测试。请注意,此命令不会执行任何操作,因为我们没有从容器内部运行它。

我们可以用wrk运行的最简单的情况是:

wrk -t2 -c5 -d5s -H 'Host: example.com' --timeout 2s http://$APP1_PRIVATE_IP:3000/

意思是:

  • -t2:使用两个单独的线程
  • -c5:打开六个连接(第一个客户端为零)
  • -d5s:运行测试五秒钟
  • -H 'Host: example.com':传递Host 标题
  • --timeout 2s:定义两秒超时
  • http://$APP1_PRIVATE_IP:3000/ 目标应用程序正在监听 $APP1_PRIVATE_IP:3000
  • 对我们的应用程序/的路径进行基准测试

这也可以描述为六个用户重复请求我们的主页五秒钟。

下图显示了这种情况:

请记住,无法将连接与真实用户进行比较,因为真实用户在查看主页时也会下载CSS,图像和JavaScript文件。

这是测试的实际命令:

让我们在我们的wrk 腾讯CVM容器中运行所描述的场景:

docker run --rm williamyeh/wrk -t2 -c5 -d5s -H 'Host: example.com' --timeout 2s http://$APP1_PRIVATE_IP:3000/

等待测试运行几秒钟,然后查看结果,我们将在下一步中对其进行分析。

第5步 - 评估输出

输出:

OutputRunning 5s test @ http://10.135.232.163:3000
  2 threads and 5 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.82ms    2.64ms  26.68ms   85.81%
    Req/Sec   550.90    202.40     0.98k    68.00%
  5494 requests in 5.01s, 1.05MB read
Requests/sec:   1096.54
Transfer/sec:    215.24KB
  • 当前配置摘要: Running 5s test @ http://10.135.232.163:3000 2 threads and 5 connections 在这里,我们可以看到我们的基准配置的简短摘要。基准测试时间为5秒,基准测试机IP为10.135.232.163,并且测试使用了两个线程。
  • 延迟和req / sec统计信息的正态分布参数: Thread Stats Avg Stdev Max +/- Stdev Latency 3.82ms 2.64ms 26.68ms 85.81% Req/Sec 550.90 202.40 0.98k 68.00% 这部分向我们展示了我们基准测试的正态分布细节 - 高斯函数将具有哪些参数。 基准并不总是具有正态分布,这就是为什么这些结果可能会产生误导。因此,请始终查看Max+/- Stdev值。如果这些值很高,那么您可以预期您的分布可能会有很重的尾巴。
  • 有关请求编号,传输数据和吞吐量的统计信息: 5494 requests in 5.01s, 1.05MB read Requests/sec: 1096.54 Transfer/sec: 215.24KB 在这里,我们看到在5.01几秒钟内,wrk可以进行5494请求和1.05MB数据传输。结合简单的math(total number of requrests/benchmark duration),我们得到1096.54每秒请求的结果。

通常,您设置的客户端越多,您应该获得的每秒请求越少。延迟也会增加。这是因为应用程序将承受更重的负载。

什么结果最好?

你的目标是保持Requests/sec尽可能高和Latency尽可能低。

理想情况下,延迟不应该太高,至少对于网页而言。当资产大约两秒或更短时,资产的页面加载时间限制是最佳的。

现在你可能会问自己: 550.90 Requests/sec3.82ms的延迟是否是一个好的结果?不幸的是,没有简单的答案。这取决于许多因素,如:

  • 客户数量,正如我们之前讨论的那样。
  • 服务器资源 - 是大型还是小型实例?
  • 为应用程序提供服务的机器数量
  • 您的服务类型 - 是提供静态文件的缓存还是提供动态响应的广告服务器?
  • 数据库类型,数据库簇大小,数据库连接类型
  • 请求和响应类型 - 它是一个小的AJAX请求还是胖API调用?
  • 还有很多其他因素

第6步 - 采取措施改善延迟

如果您对服务表现不满意,您可以:

  • 调整您的服务 - 检查您的代码,看看可以更有效地完成哪些工作
  • 检查您的数据库,看看它是否是您的瓶颈
  • 垂直扩展 - 为您的计算机添加资源
  • 水平扩展 - 添加服务的另一个实例并将其添加到负载均衡器
  • 添加缓存层

请记住在对其进行更改后对您的服务进行基准测试 - 只有这样才能确保您的服务得到改进。

你可能会想,如果没有Lua的话,那事情可能就是这样了。。。

使用Lua脚本模拟高级HTTP请求

因为wrk有一个内置的LuaJIT(Lua的即时编译器),所以可以使用Lua脚本进行扩展。正如介绍中所提到的,这为wrk增加了许多功能。

在wrk中使用Lua脚本很简单。只需将文件路径附加到-s标志即可。

因为我们在Docker中使用wrk,所以我们必须先与容器共享此文件。这可以通过Docker的-v选项实现。

wrk的Lua脚本的一部分

在通用形式中,使用调用的脚本test.lua,会使整个命令可能如下所示:

docker run --rm -v `pwd`/scripts:/scripts williamyeh/wrk -c1 -t1 -d5s -s /scripts/test.lua http://$APP1_PRIVATE_IP:3000

我们在前面的步骤中解释了wrk命令及其选项。这个命令不会增加太多; 只是脚本的路径和一些额外的命令告诉Docker如何在容器外找到它。

--rm标志将在停止后自动删除容器。

但我们真的知道如何编写Lua脚本吗?不要害怕; 你会轻松学习它。我们将在这里介绍一个简单的示例,您可以自己运行自己的更高级脚本。

首先让我们谈谈反映wrk内部逻辑的预定脚本结构。下图说明了一个线程:

wrk执行以下执行阶段:

  • 解析域的IP地址
  • 从线程设置开始
  • 执行压力测试阶段,称为运行阶段
  • 最后一步简称为完成

使用多个线程时,您将拥有一个分辨率阶段和一个完成阶段,但有两个设置阶段和两个运行阶段:

此外,运行阶段可以分为三个步骤:initrequestresponse

根据提供的图表和文档,我们可以在Lua脚本中使用以下方法:

  • setup(thread):所有线程初始化但尚未启动时执行。用于将数据传递给线程
  • init(args):初始化每个线程时调用 此函数接收脚本的额外命令行参数,我们必须用--将该参数与wrk参数分开。 例: wrk -c3 -d1s -t2 -s /scripts/debug.lua http://$APP1_PRIVATE_IP:3000 -- debug true
  • request():需要为每个请求返回HTTP对象。在这个函数中,我们可以修改方法,标题,路径和正文 使用wrk.format辅助函数来塑造请求对象。 例: return wrk.format(method, path, headers, body)
  • response(status, headers, body):响应回来时调用
  • done(summary, latency, requests):在完成所有请求并计算统计信息时执行 在此功能中,可以使用以下属性: 属性描述summary.duration运行持续时间,以微秒为单位summary.requests完成的请求总数summary.bytes收到的总字节数summary.errors.connect总套接字连接错误summary.errors.read总套接字读错误summary.errors.write总套接字写错误summary.errors.status总HTTP状态代码> 399summary.errors.timeout总请求超时latency.min测试期间达到的最小延迟值latency.max测试期间达到的最大延迟值latency.mean测试期间达到的平均延迟值latency.stdev潜伏期标准差latency:percentile(99.0)第99百分位值latency[i]请求的原始延迟数据 i

每个线程都有自己的Lua上下文,并在其中有自己的局部变量。

现在我们将通过一些实际示例,但您可以在wrk项目的scripts目录中找到更多有用的基准测试脚本。

示例:POST请求

让我们从最简单的例子开始,我们模拟一个POST请求。

POST请求通常用于将数据发送到服务器。这可用于基准测试:

  • HTML表单处理程序:使用HTML表单在action属性中的地址: <form action="/login.php"> ... </form>
  • POST API端点:如果您有一个restful API,请创建文章的地方使用该端点: POST /articles

首先在wrk1腾讯CVM 上创建一个scripts/post.lua文件。

cd ~
mkdir scripts
nano scripts/post.lua

添加以下内容:

wrk.method = "POST"
wrk.body   = "login=sammy&password=test"
wrk.headers["Content-Type"] = "application/x-www-form-urlencoded"

这个脚本非常简单,甚至没有使用任何提到的方法,我们就修改了全局wrk对象属性。

我们将请求方法更改为POST,添加了一些登录参数,并将Content-Type标头指定为HTML表单使用的MIME类型。

现在是关键时刻 - 使用此命令对应用程序进行基准测试(在wrk1 腾讯CVM上执行):

docker run --rm -v `pwd`/scripts:/scripts williamyeh/wrk -c1 -t1 -d5s -s /scripts/post.lua http://$APP1_PRIVATE_IP:3000

输出:

OutputRunning 5s test @ http://10.135.232.163:3000
  1 threads and 1 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.04ms  718.38us  12.28ms   90.99%
    Req/Sec     1.02k   271.31     1.52k    66.00%
  5058 requests in 5.00s, 0.97MB read
Requests/sec:   1011.50
Transfer/sec:    198.55KB

输出类似于我们之前看到的输出。

请注意,我们仅使用一个连接进行基准测试。这对应于只有一个用户想要连续登录,传递用户名和密码的情况。这不是请求任何CSS,图像或JavaScript文件。

对于更现实的场景,您应该增加客户端和线程的数量,同时观察延迟参数,以查看应用程序验证用户凭据的速度。

示例:多个URL路径

另一个常见需求是同时测试应用程序的多个路径。

让我们创建一个名为paths.txt的文件,该文件可以在data目录中调用,并添加我们想要在基准测试期间使用的所有路径。

cd ~
mkdir data
nano data/paths.txt

查找以下示例data/paths.txt

/feed.xml
/contact/
/about/
/blog/
/2015/04/21/nginx-maintenance-mode/
/2015/01/06/vagrant-workflows/
/2014/12/10/top-vagrant-plugins/

然后抓住这个简单的脚本并将其保存为scripts/multiple-url-paths.lua

-- Load URL paths from the file
function load_url_paths_from_file(file)
  lines = {}

  -- Check if the file exists
  -- Resource: http://stackoverflow.com/a/4991602/325852
  local f=io.open(file,"r")
  if f~=nil then
    io.close(f)
  else
    -- Return the empty array
    return lines
  end

  -- If the file exists loop through all its lines
  -- and add them into the lines array
  for line in io.lines(file) do
    if not (line == '') then
      lines[#lines + 1] = line
    end
  end

  return lines
end

-- Load URL paths from file
paths = load_url_paths_from_file("/data/paths.txt")

print("multiplepaths: Found " .. #paths .. " paths")

-- Initialize the paths array iterator
counter = 0

request = function()
  -- Get the next paths array element
  url_path = paths[counter]

  counter = counter + 1

  -- If the counter is longer than the paths array length then reset it
  if counter > #paths then
    counter = 0
  end

  -- Return the request object with the current URL path
  return wrk.format(nil, url_path)
end

虽然本教程并未尝试详细讲授Lua脚本,但如果您阅读脚本中的注释,则可以很好地了解它的作用。

multiple-url-paths.lua脚本将打开该/data/paths.txt文件,如果此文件包含路径,则会将它们保存到内部paths数组中。然后,对于每个请求,将采用下一个路径。

要运行此基准测试,请使用以下命令(在wrk1 腾讯CVM上执行)。您会注意到我们正在添加一些换行符以便于复制:

docker run --rm \
           -v `pwd`/scripts:/scripts \
           -v `pwd`/data:/data \
           williamyeh/wrk -c1 -t1 -d5s -s /scripts/multiple-url-paths.lua http://$APP1_PRIVATE_IP:3000

输出:

Outputmultiplepaths: Found 7 paths
multiplepaths: Found 7 paths
Running 5s test @ http://10.135.232.163:3000
  1 threads and 1 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     0.92ms  466.59us   4.85ms   86.25%
    Req/Sec     1.10k   204.08     1.45k    62.00%
  5458 requests in 5.00s, 1.05MB read
Requests/sec:   1091.11
Transfer/sec:    214.17KB

使用JSON和YAML的Avanced请求

现在您可能会认为其他基准测试工具也可以执行这些类型的测试。但是,wrk还能够使用JSON或YAML格式处理高级HTTP请求。

例如,您可以加载JSON或YAML文件,该文件详细描述了每个请求。

作者在作者的技术博客上发布了一个带有JSON请求的高级示例。

您可以使用wrk和Lua对您能想到的任何类型的HTTP请求进行基准测试。

结论

阅读本文后,您应该能够使用wrk来对您的应用程序进行基准测试。作为旁注,您还可以看到Docker的优点以及它如何极大地最小化您的应用程序和测试环境的设置。

最后,您可以使用带有wrk的Lua脚本进行高级HTTP请求。

更多 Ubuntu教程请前往腾讯云+社区学习更多知识。


参考文献:《 How To Benchmark HTTP Latency with wrk on Ubuntu 14.04》

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 如何重置MySQL或MariaDB Root密码

    忘记密码发生在我们大多数人身上。如果您忘记或丢失了MySQL或MariaDB数据库的root密码,如果您有权访问服务器和启用了sudo用户帐户,您仍然可以获得访...

    黑色技术
  • 通过SSHFS远程挂载文件夹,方便远程coding!

    很多情况下,从服务器传输文件会得很麻烦。想象一下开发使用场景,您正本地为服务器编写软件,并自己将脚本重复上传到服务器进行测试。这可能会变得非常麻烦。但是,有一种...

    黑色技术
  • 如何在Ubuntu 16.04上保护OrientDB数据库

    OrientDB是一个多模型的NoSQL数据库,支持文档和图形数据库。它是一个Java应用程序,可以在任何操作系统上运行。它也完全支持ACID,支持多主复制。

    黑色技术
  • HTTP 压测工具 wrk2 安利指南

    最近的工作一直在与服务端性能优化打交道,QPS(每秒查询率)的苛刻要求让我这个以前也就用 node.js 写写博客的人深刻地感觉到以前做的东西就是个玩具。所以最...

    逆葵
  • HTTP 压力测试工具 wrk

    简介 wrk 是一个HTTP压力测试工具,根据官方的介绍,他有2个明显的特点: 集成了多线程设计与事件通知系统(如 epoll、kqueue)提升并发量 可以通...

    dys
  • 对 wrk Latency Distribution 不准确的分析

    wrk 是一个非常棒的 HTTP 压力测试工具,构建在 Redis、NGINX、Node.js 和 LuaJIT 这几个开源项目的基础之上,充分利用了他们在事件...

    温铭@APISIX
  • 跟我一起 自己种一颗 AVL树(平衡二叉搜索树)吧!

    我也看了些资料,大部分都是说“霸王硬上弓”,插入、旋转、插入、旋转··· 我感觉这样挺繁琐的,创建一棵树就要不断的旋转,旋转,而且由于数据的无序性,每次插入都...

    看、未来
  • greenplum gptransfer命令使用

    https://gpdb.docs.pivotal.io/510/utility_guide/admin_utilities/gptransfer.html

    小徐
  • Golang Leetcode 563. Binary Tree Tilt.go

    更多内容请移步我的repo:https://github.com/anakin/golang-leetcode

    anakinsun
  • LeetCode:110_Balanced Binary Tree | 平衡二叉树 | Easy

    要求:判断一棵树是否是平衡二叉树 Given a binary tree, determine if it is height-balanced. For ...

    CloudDeveloper

扫码关注云+社区

领取腾讯云代金券