文档结构  
翻译进度:已翻译     翻译赏金:5 元 (?)    ¥ 我要打赏

这篇文章由Ivan Enderlin 和 Wern Ancheta进行同行评审。 感谢SitePoint所有同行评审们将SitePoint 内容做得这么好!

现在构建一个简单的Web应用程序已经不是那么难了。 网络开发社区里的人都很友好,而且在Stack Overflow或者类似的平台上有大量的相关讨论,还有各种各样的网站提供相关课程和教程

几乎任何人都能在本地构建一个应用,然后将其部署到服务器上,并自豪地展示给你的朋友。我想你已经做到了这些,并且你的项目已经广为传播, 所以很自然的你来到了这里,因为你想学习一些东西,来确保你的应用程序能够承受更高的流量。

第 1 段(可获 1.48 积分)

如果我们把Web应用程序想成一个黑盒子,那事情就会变得很简单了 – 应用会等待请求,并处理它们,然后以某种资源格式的形式(HTML、JSON、XML等)返回响应结果。 有人可能会想:“这很简单吧,我们应该能够很轻松的扩展我们的应用。”不幸的是,网页开发的世界并不总是一帆风顺,当你的网站的流量在攀升时你会遇到各种各样的性能问题!而你也将会随着时间不断学习和提升你的技能和应用。本文的初衷就是为了帮助你提早加速这个过程,在本文中,我将会介绍使用Siege测试应用程序的一些基本概念 (回归、负载和压力测试)以及我在测试自己的web应用程序时所用到的一些技巧。

第 2 段(可获 1.66 积分)

Vector image of catapult

测试类型

假设我们要实现每日100万个独立用户的访问目标。 我们应该如何为这么大的流量做准备? 在正常的流量或高峰期时,我们如何确保程序不会中断? 这种类型的测试称为负载 测试,因为我们知道我们的应用程序需要承载多少流量 - 负载。 如果你想将你的应用推到极限并不断施压,直到它奔溃,你就是在进行压力测试。

除此之外,您是否知道部署的代码更改可能会影响性能? 一个简单的更新可以在很大程度上降低或改善高流量Web应用的性能,你甚至不知道发生了什么,或者为什么直到风暴结束。 为了确保应用程序在更改之前和之后执行相同的操作,我们会进行回归 测试。

第 3 段(可获 1.94 积分)

回归测试的另一个动机是基础设施的改变:无论什么原因,您可能希望从供应商A转到供应商B(或从Apache切换到Nginx)。 您知道您的应用程序通常每分钟处理N个请求(平均值)以及正常的流量(可以通过快速查看分析工作实现)。 您期望您的应用程序在部署供应商B的服务器后将表现得相同(或更好)。 你确定吗? 你会冒这个风险吗? 你已经拥有了所有你需要的数据,不要猜测! 在部署之前测试您的新设置,您就能睡得更香!

第 4 段(可获 1.31 积分)

在使用虚拟请求开始随机点击应用程序之前,您应该知道测试不是一件容易的事情,您从Siege或任何其他测试工具获取的数据应该用于分析相对更改的参考。我不建议您在本地运行Siege和应用程序五分钟,然后得出您的应用程序可以在几秒钟内处理几百或几千个请求这样的结论。

成功测试的步骤

  • 计划

    想一想你想测试什么。你期望得到什么结果。有多少流量,测试哪些网址,使用哪些有效载荷?在测试之前就定义参数,不要随便点击你的应用程序。

  • 准备

    确保您的环境尽可能隔离 - 对于每个测试运行,使用相同的环境进行测试。有关如何完成此操作的良好指南可以在如何设置PHP环境这本书中找到。

  • 分析和学习

    从数字中获取一些信息,并做出有根据的决定。结果应始终在其上下文中进行评估 - 不要妄下结论。至少检查两次。

第 5 段(可获 2.26 积分)

Siege入门

Siege是一款非常棒的用于对网络应用进行基准测试和普通测试的工具。 它模拟并发用户在给定的URL(或多个URL)上请求资源,并允许用户大量定制测试参数。 运行siege --help以查看所有可用的选项; 我们将在下面详细介绍其中的一些内容。

准备测试应用程序

使用Siege,您可以测试应用程序在代码(或基础架构)更改之间的稳定性,性能和改进。 在您发布一张有毒的猫的照片后,您还可以使用它来确保您的WordPress网站可以处理您期望的峰值,或用于设置和评估HTTP缓存系统(如Varnish)的好处

第 6 段(可获 1.44 积分)

对于本文中的测试,我将使用部署到法兰克福的一个Digital Ocean节点的略微修改的Symfony Demo应用程序,并使用安装在纽约的第二个Digital Ocean节点上的SIEGE 4.0.2。

如前所述,尽可能地将应用程序和测试服务器隔离起来至关重要。 如果您在本地计算机上运行它们,因为运行的其他进程(电子邮件客户端,消息工具,守护程序)可能会影响性能,则不能保证每次测试都有相同的环境; 即使是像 Homestead Improved这样的高质量的虚拟机,资源可用性也不能得到100%的保证(如果你不想在你的应用程序的负载测试阶段花钱,那么这些孤立的虚拟机也是一个可用的选择)。

第 7 段(可获 1.61 积分)

Symfony Demo应用程序在开箱即用时非常简单和快捷的。 在现实生活中,我们正在处理复杂和缓慢的应用程序,所以我决定在单个帖子的边栏添加两个模块:最近的帖子(10个最新帖子)和热门帖子(10个评论最多的帖子)。 通过这样做,我向应用程序增加了更多的复杂性,该应用程序现在至少查询数据库三次。 这个想法是尽可能地获得一个真实的状况。 数据库已经填充了62,230篇虚拟帖子和大约1,445,505个评论。

学习基础知识

运行命令siege SOME-URL将使Siege开始使用默认参数测试URL。 初始消息之后...

第 8 段(可获 1.51 积分)
** Preparing 25 concurrent users for battle.
The server is now under siege...

...屏幕将开始充满有关发送请求的信息。 您的第一反应可能是通过按下CTRL + C来停止执行,此时它将停止测试并输出结果。

在我们继续之前,普通测试/基准测试网络应用程序时,您应该牢记一件事。 考虑发送到Symfony演示应用程序博客页面/en/blog/的单个HTTP请求的生命周期。 服务器将生成一个HTTP响应,包含状态200(OK)和body体中的HTML内容和对图像和其他资产(样式表,JavaScript文件,...)的引用。 Web浏览器处理这些引用,并在后台请求呈现网页所需的所有资产。 我们总共需要多少HTTP请求呢?

第 9 段(可获 1.58 积分)

要得到答案,让我们使用siege 单独测试一下并分析结果。 当我运行siege -c=1 --reps=1 http://sfdemo.loc/en/blog/时,我已经在终端中打开了我的应用程序的访问日志(tail -f var/logs/access.log)。 基本上,我会告诉Siege:“使用一个用户(-c = 1)为URL http://sfdemo.loc/en/blog/ 运行测试一次(-reps = 1)”。 我可以同时在日志和Siege的输出中看到请求。

 siege -c=1 --reps=1 http://sfdemo.loc/en/blog/

** Preparing 1 concurrent users for battle.
The server is now under siege...
HTTP/1.1 200     1.85 secs:   22367 bytes ==> GET  /en/blog/
HTTP/1.1 200     0.17 secs:    2317 bytes ==> GET  /js/main.js
HTTP/1.1 200     0.34 secs:   49248 bytes ==> GET  /js/bootstrap-tagsinput.min.js
HTTP/1.1 200     0.25 secs:   37955 bytes ==> GET  /js/bootstrap-datetimepicker.min.js
HTTP/1.1 200     0.26 secs:   21546 bytes ==> GET  /js/highlight.pack.js
HTTP/1.1 200     0.26 secs:   37045 bytes ==> GET  /js/bootstrap-3.3.7.min.js
HTTP/1.1 200     0.44 secs:  170649 bytes ==> GET  /js/moment.min.js
HTTP/1.1 200     0.36 secs:   85577 bytes ==> GET  /js/jquery-2.2.4.min.js
HTTP/1.1 200     0.16 secs:    6160 bytes ==> GET  /css/main.css
HTTP/1.1 200     0.18 secs:    4583 bytes ==> GET  /css/bootstrap-tagsinput.css
HTTP/1.1 200     0.17 secs:    1616 bytes ==> GET  /css/highlight-solarized-light.css
HTTP/1.1 200     0.17 secs:    7771 bytes ==> GET  /css/bootstrap-datetimepicker.min.css
HTTP/1.1 200     0.18 secs:     750 bytes ==> GET  /css/font-lato.css
HTTP/1.1 200     0.26 secs:   29142 bytes ==> GET  /css/font-awesome-4.6.3.min.css
HTTP/1.1 200     0.44 secs:  127246 bytes ==> GET  /css/bootstrap-flatly-3.3.7.min.css

Transactions:                  15 hits
Availability:              100.00 %
Elapsed time:                5.83 secs
Data transferred:            0.58 MB
Response time:                0.37 secs
Transaction rate:            2.57 trans/sec
Throughput:                0.10 MB/sec
Concurrency:                0.94
Successful transactions:          15
Failed transactions:               0
Longest transaction:            1.85
Shortest transaction:            0.16
第 10 段(可获 0.84 积分)

访问日志是这样的:

107.170.85.171 - - [04/May/2017:05:35:15 +0000] "GET /en/blog/ HTTP/1.1" 200 22701 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:17 +0000] "GET /js/main.js HTTP/1.1" 200 2602 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:17 +0000] "GET /js/bootstrap-tagsinput.min.js HTTP/1.1" 200 49535 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:17 +0000] "GET /js/bootstrap-datetimepicker.min.js HTTP/1.1" 200 38242 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:18 +0000] "GET /js/highlight.pack.js HTTP/1.1" 200 21833 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:18 +0000] "GET /js/bootstrap-3.3.7.min.js HTTP/1.1" 200 37332 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:18 +0000] "GET /js/moment.min.js HTTP/1.1" 200 170938 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:19 +0000] "GET /js/jquery-2.2.4.min.js HTTP/1.1" 200 85865 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:19 +0000] "GET /css/main.css HTTP/1.1" 200 6432 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:19 +0000] "GET /css/bootstrap-tagsinput.css HTTP/1.1" 200 4855 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:19 +0000] "GET /css/highlight-solarized-light.css HTTP/1.1" 200 1887 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:20 +0000] "GET /css/bootstrap-datetimepicker.min.css HTTP/1.1" 200 8043 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:20 +0000] "GET /css/font-lato.css HTTP/1.1" 200 1020 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:20 +0000] "GET /css/font-awesome-4.6.3.min.css HTTP/1.1" 200 29415 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
107.170.85.171 - - [04/May/2017:05:35:20 +0000] "GET /css/bootstrap-flatly-3.3.7.min.css HTTP/1.1" 200 127521 "-" "Mozilla/5.0 (unknown-x86_64-linux-gnu) Siege/4.0.2"
第 11 段(可获 0.08 积分)

我们可以看到,尽管我们告诉 Siege 测试一次 URL,但是执行了15个事务(请求)。如果你想知道什么是事务,你应该查看 Github 页面

事务的特征在于服务器为客户端打开套接字,处理请求,通过线路发送数据,并在完成时关闭套接字。

所以 Siege 并不会为提供的 URL 发送单一的 HTTP GET 请求,它会为指定的 URL 引用的所有相关资源生成 HTTP GET 请求。我们应该清醒的是 Siege 并不会执行 JavaScript,所以这里并不包括 AJAX 请求。同时我们应该记住的是浏览器能够缓存静态文件(图片,字体,JS文件)。

第 12 段(可获 1.63 积分)

版本 4.0 以后,可以通过修改位于 ~/.siege/siege.conf 的配置文件并设置parser = false 来修改这种行为。

注意: 依据你正在使用的 Siege 版本,甚至工具,默认的行为会有所不同。如果你正在使用 Siege 以外的工具,在你得出结论之前检查真正的单一测试是什么(对指定 URL 的单一请求,或者对指定 URL 的一次请求及其所有资源的子请求)

由上面的测试输出我们可以看到在 ~6 秒时间内,Siege 生成了15次请求(事务),得到了0.58MB 100% 可用的传输数据或是 15/15 成功事务--“成功事务是指服务器返回代码小于400的次数。相应地,重定向被认为是成功事务。”

第 13 段(可获 1.71 积分)

响应时间是指我们发出所有请求并得到响应所需要的平均时间。事务率和吞吐量能够告诉我们应用的容量(即我们的应用在给定时间内能够处理多少流量)。

让我们用15个用户来重复这个测试:

siege --concurrent=15 --reps=1 sfdemo.loc/en/blog/

Transactions:                 225 hits
Availability:              100.00 %
Elapsed time:                6.16 secs
Data transferred:            8.64 MB
Response time:                0.37 secs
Transaction rate:           36.53 trans/sec
Throughput:                1.40 MB/sec
Concurrency:               13.41
Successful transactions:         225
Failed transactions:               0
Longest transaction:            1.74
Shortest transaction:            0.16
第 14 段(可获 0.59 积分)

通过增加测试负载,我们使得我们的应用显示出其能力。我们可以看到我们的应用可以很好地处理来自一个博客页面的15个用户的请求,平均响应时间为 0.37 秒。默认情况下,Siege 会有 1到3秒的随机请求延时。通过设置 --delay=N 参数,我们可以影响请求之间的延时随机值(设置最大延时)。

并发

并发也许是最令人迷惑的结果属性,让我们来解释它。文档描述:

并发是同时连接的平均数,并发数增加,服务器性降低。

第 15 段(可获 1.35 积分)

FAQ 部分,我们可以看到并发是如何计算的:

并发是总的事务除以总的消耗时间。所以,如果我们在10秒内完成了100个事务,我们的并发就是 10.00.

另一个对于并发的不错解释在 official website:

我们可以使用一个明显的例子演示这一点。我为一个具有两个节点的集群网站运行 Siege 。我的并发是 6.97。然后我移除一个节点并对相同的页面运行相同的测试,我的并发提高到 18.33。同时我的消耗时间增加了 65%

第 16 段(可获 1.24 积分)

让我们由另一个不同的角度来看一下 -- 如果你是一个餐厅的拥有者,在做出变化之前想要评估业务表现,你可以度量一段时间内开放订单的平均数(例如,等待将会的订单 -- 请求)。在上面的第一个例子中,开放订单的平均数为 7,但是如果你解雇一个的厨房员工(例如,拿走一个节点),你的并发数将会提高到 18。记住,我们希望在相同的环境下进行测试,所以顾客的数量与订单的密度应该是相同的。服务员可以以高频率接受订单(类似 web 服务器),但是处理时间较慢,而你的厨房员工(你的应用)处于超载与忙于交付订单状态。

第 17 段(可获 1.65 积分)

使用 Siege 进行性能测试

要了解我们应用的性能的真实概貌,我使用不同的并发用户数运行 Siege 5分钟并比较结果。因为博客首页是一个具有简单数据库查询的尾端,在接下来的测试中我将会测试一个文章页面,因为他们速度更慢且更为复杂。

siege --concurrent=5 --time=5M http://sfdemo.loc/en/blog/posts/vero-iusto-fugit-sed-totam.`

当测试运行时,我可以在我的应用的服务器上运行 top 来查看状态。 MySQL 正在努力工作:

%CPU %MEM     TIME+ COMMAND
96.3 53.2   1:23.80 mysqld
第 18 段(可获 1.08 积分)

这是我们所预期的,因为每次应用渲染一个文章页面时,会执行很多次数据库查询:

  1. 读取文章信息以及相关的评论
  2. 读取最新发布的 10 篇文章
  3. 执行一个文章表和大评论表的联合查询,并根据评论数获取最受欢迎的 10 篇文章

首个测试是以 5 个并发用户进行的,数字表现很一般:

siege --concurrent=5 --time=5M http://sfdemo.loc/en/blog/posts/vero-iusto-fugit-sed-totam.

Transactions:                1350 hits
Availability:              100.00 %
Elapsed time:              299.54 secs
Data transferred:           51.92 MB
Response time:                1.09 secs
Transaction rate:            4.51 trans/sec
Throughput:                0.17 MB/sec
Concurrency:                4.91
Successful transactions:        1350
Failed transactions:               0
Longest transaction:           15.55
Shortest transaction:            0.16
第 19 段(可获 0.88 积分)

Siege 能够在5分钟内完成1350个事务。因为我们有 15 个事务/页面 载入,我们可以很容易计算得到我们的应用能够在 5分钟内处理 90个页面载入或是18个页面载入/1分钟,或是 0.3 个页面载入/秒。通过将事务率与每页的事务数相除,我们也可以计算得到相同的结果 4,51 / 15 = 0,3.

当然,这并不是多大的吞吐量,但是至少我们知道瓶颈在哪里(数据库查询)并且我们有优化应用要比较的参考。

让我们多运行一些测试来了解在更大的压力之下我们应用的工作状态如何。这一次我们并并发用户数设置为10,在测试的前几分钟内我们可以看到大量的 HTTP 500 错误:在稍大的流量之下,应用开始丢包。现在让我们来比较一下在5,10与15个并发用户的 Siege 测试下应用的性能。

第 20 段(可获 2.13 积分)

 

siege-comparison-no-cache

并发设置为5,10与15的 Siege 结果比较

注意,随着并发数的增加我们应用的性能是如何降低的。当有15个并发用户时,程序完全无响应--例如,15个野蛮用户就是攻破你堡垒的全部力量。我们是工程师,我们不能被挑战吓哭,我们要解决它们!

记住,这些测试是自动进行的,并且我们将我们的应用置于压力环境之下。在真实生活中,用户并不会像疯子一样仅是点击刷新按钮,他们处理(例如阅读)你提供的内容,所以在两次请求之间存在一定的延时。

第 21 段(可获 1.38 积分)

Cache 来拯救

现在我们了解了我们应用中的某些问题 - 我们过于频繁地查询数据库。我们确实需要在每次单一请求时获取流行与最近的文章列表吗?当然不需要,所以我们可以在应用层添加一个缓存层(例如 Redis)并且缓存流行与最近的文章列表。本文并不是关于缓存的(要了解缓存,可以查 这里 ),所以我们为单一的文章页面添加完全响应缓存。

Tdemo 应用已经启用了 Symfony HTTP Cache ,我们仅需要为我们返回的 HTTP 响应设置 TTL 头部。

第 22 段(可获 1.46 积分)
$response->setTtl(60);

让我们使用5,10,与15个并发用户重复测试,并且了解添加缓存如何影响性能。很明显,我们期望在缓存预热之后应用的性能能够增加。同时我们在测试之间至少等待1分钟以使得缓存失效。

注意: 小心缓存,特别是 web 应用(oops example) 中 IRT 保护部分,并且时刻记住 它是计算机科学中两件难事之一

结果: 通过添加60s缓存,应用的稳定性与性能明显改善。看一下下列图表中的结果。

第 23 段(可获 1.35 积分)
 C=5C=10C=15
Transactions4566 hits8323 hits12064 hits
Availability100.00 %100.00 %100.00 %
Elapsed time299.86 secs299.06 secs299.35 secs
Data transferred175.62 MB320.42 MB463.78 MB
Response time0.31 secs0.34 secs0.35 secs
Transaction rate15.23 trans/sec27.83 trans/sec40.30 trans/sec
Throughput0.59 MB/sec1.07 MB/sec1.55 MB/sec
Concurrency4.749.5114.31
Successful transactions4566832312064
Failed transactions000
Longest transaction4.325.734.93

使用 HTTP 缓存 ttl 设置为60秒的单一文章 URL 的 Siege 测试。

Transactions before and after adding cache

使用缓存,应用能够处理更多事务。

第 24 段(可获 1.63 积分)

Response time before and after adding cache

正如所期望的,在添加缓存之后响应时间降低而稳定性不受浏览的影响。

真实感觉

如果你希望得到在压力环境下使用你的应用的真实感觉,你可以运行 Siege 并在浏览器中运行你的应用。 Siege 会将该应用置于压力之下,而且你能够得到真正的用户体验。尽管这是一个主观方法,我认为对于开发者中的大多数,它是一个令人大开眼界的体验。试一下吧。

替代工具

Siege 并不是对 web 应用进行负载测试与基准测试的唯一工具。让我们使用 ab 对应用进行快速测试。

第 25 段(可获 1.35 积分)

Ab

ab or Apache HTTP server benchmarking tool 是另一个很好的工具。它有很好的文档与大量的选项,尽管它并不支持使用 URL 文件,解析与请求引用的资源,也不像 Siege 那样支持随机延时。

如果我们对单一的文章页面(无缓存)运行 ab 测试,结果如下:

ab -c 5 -t 300 http://sfdemo.loc/en/blog/posts/vero-iusto-fugit-sed-totam.
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking sfdemo.loc (be patient)
Finished 132 requests


Server Software:        Apache/2.4.18
Server Hostname:        sfdemo.loc
Server Port:            80

Document Path:          /en/blog/posts/vero-iusto-fugit-sed-totam.
Document Length:        23291 bytes

Concurrency Level:      5
Time taken for tests:   300.553 seconds
Complete requests:      132
Failed requests:        0
Total transferred:      3156000 bytes
HTML transferred:       3116985 bytes
Requests per second:    0.44 [#/sec] (mean)
Time per request:       11384.602 [ms] (mean)
Time per request:       2276.920 [ms] (mean, across all concurrent requests)
Transfer rate:          10.25 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       81   85   2.0     85      91
Processing:  9376 11038 1085.1  10627   13217
Waiting:     9290 10953 1084.7  10542   13132
Total:       9463 11123 1085.7  10712   13305

Percentage of the requests served within a certain time (ms)
  50%  10712
  66%  11465
  75%  12150
  80%  12203
  90%  12791
  95%  13166
  98%  13302
  99%  13303
 100%  13305 (longest request)
第 26 段(可获 0.66 积分)

我们打开缓存之后,结果是这样的:

ab -c 5 -t 300 http://sfdemo.loc/en/blog/posts/vero-iusto-fugit-sed-totam.
This is ApacheBench, Version 2.3 <$Revision: 1706008 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking sfdemo.loc (be patient)
Completed 5000 requests
Finished 5373 requests


Server Software:        Apache/2.4.18
Server Hostname:        sfdemo.loc
Server Port:            80

Document Path:          /en/blog/posts/vero-iusto-fugit-sed-totam.
Document Length:        23351 bytes

Concurrency Level:      5
Time taken for tests:   300.024 seconds
Complete requests:      5373
Failed requests:        0
Total transferred:      127278409 bytes
HTML transferred:       125479068 bytes
Requests per second:    17.91 [#/sec] (mean)
Time per request:       279.196 [ms] (mean)
Time per request:       55.839 [ms] (mean, across all concurrent requests)
Transfer rate:          414.28 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       81   85   2.1     85     106
Processing:   164  194 434.8    174   13716
Waiting:       83  109 434.8     89   13632
Total:        245  279 434.8    259   13803

Percentage of the requests served within a certain time (ms)
  50%    259
  66%    262
  75%    263
  80%    265
  90%    268
  95%    269
  98%    272
  99%    278
 100%  13803 (longest request)
第 27 段(可获 0.11 积分)

我喜欢 ab 在报告中显示的时间分割与状态。我可以立即看到我们请求中的 50% 的服务响应时间低于 259ms (vs 无缓存为10.712ms ) 且其中的 99% 低于 278ms (vs 无缓存为13.305ms ) ,这个结果是可以接受的。再一次强调,测试结果是在其语境内部且相对前一个状态而评估得到的。

使用 Siege 进行高级负载测试

现在我们已经掌握了负载与回归测试的基础,是时候进入下一步了。到目前为止,我们使用生成的请求访问一个 URL,而且我们看到,一旦响应被缓存,我们的应用可以轻松应对大流量。

第 28 段(可获 1.44 积分)

在真实生活中,事情更为复杂 -- 用户在网站中随机浏览,访问 URL 并处理内容。对于 Siege,我最喜欢的就是可以使用 URL 文件,我可以在文件中放置多个在测试过程中随机使用的 URL。

步骤 1: 计划测试

我们需要在用户访问最多的 URL 列表进行测试。我们应该考虑的第二件事情是用户行为的动态性,例如他们点击链接的速度有多快。

我基于我的分析工具或是服务器日志文件的数据创建一个 URL 文件。可以使用访问日志解析工具,例如 Web server access Log Parser 来解析 Apache 访问日志,并生成一个按流行度排序的 URL 列表。我选取前 N (20, 50, 100 …) 个 URL 并将其放入文件中。如果某些 URL 的访问次数高于其他 URL (例如,登陆页面或是病毒文章),我们应该调整概率从而使得 Siege 更多地访问这些 URL。

第 29 段(可获 2.31 积分)

假设我们在过去N天内拥有以下访问次数的网址:

  • Landing page / Home page – 30.000
  • Article A – 10.000
  • Article B – 2.000
  • Article C – 50.000
  • About us – 3.000

我们可以规范访问次数,并得到如下列表:

  • Landing page / Home page – 32% (30.000 / 95.000)
  • Article A – 11% (10.000 / 95.000)
  • Article B – 2% (2.000 / 95.000)
  • Article C – 52% (50.000 / 95.000)
  • About us – 3% (3.000 / 95.000)

现在我们可以创建一个URL文件,有100个URL(行),有32个x主页URL,52个x文章C URL等等。 您可以调整最终文件以获得更多的随机性,并保存它。

第 30 段(可获 1.51 积分)

由你的分析工具中获取平均会话时间与每次会话的页面来计算两次请求之间的平均延时。如果平均会话时长为2分钟而每次会话用户平均访问8页,简单的数学可以告诉我们平均延时为15秒(120秒/8页 = 15秒/页)。

最后,我禁止资源解析与请求,因为我在生产环境中缓存静态文件并由另一个服务器提供服务。正如前面所提到的,通过位于 ~/.siege/siege.conf 的 Siege 配置文件中设置 parser = false 来关闭解析器。

第 31 段(可获 1.18 积分)

步骤 2: 准备并运行测试

因为我现在正在处理随机情况,增加测试时长从而得到更多的相关结果会是一个好主意。通过将最大延时设置为15秒与50个并行用户,我将运行 Siege 20分钟。我将使用不同的概率测试博客首页与10篇文章。

因为我不希望网络流量冲击具有空缓存的应用,我将在使用下面的命令之前通过请求所有 URL 来预热应用的缓存

siege -b --file=urls.txt -t 30S -c 1

现在我们准备好将我们的应用置于某些严格的压力之下。如果我们使用 --internet 开关, Siege 将会随机由文件中选择 URL。关闭些开关,Siege 将会顺序选择 URL。让我们开始吧。

第 32 段(可获 1.69 积分)
siege --file=urls.txt --internet --delay=15 -c 50 -t 30M

Lifting the server siege...
Transactions:               10931 hits
Availability:               98.63 %
Elapsed time:             1799.88 secs
Data transferred:          351.76 MB
Response time:                0.67 secs
Transaction rate:            6.07 trans/sec
Throughput:                0.20 MB/sec
Concurrency:                4.08
Successful transactions:       10931
Failed transactions:             152
Longest transaction:           17.71
Shortest transaction:            0.24

或者在Siege中有60个并发用户:

第 33 段(可获 0.1 积分)
siege --file=urls.txt --delay=15 -c 60 -t 30M
Transactions:               12949 hits
Availability:               98.10 %
Elapsed time:             1799.20 secs
Data transferred:          418.04 MB
Response time:                0.69 secs
Transaction rate:            7.20 trans/sec
Throughput:                0.23 MB/sec
Concurrency:                4.99
Successful transactions:       12949
Failed transactions:             251
Longest transaction:           15.75
Shortest transaction:            0.21

我们可以看到修改的 Symfony Demo 应用 (缓存开启) 可以更好地处理测试,它平均能够在0.7秒时间内每秒处理7.2个请求(注意,我们正在使用仅有 512 RAM 的单核 Digital Ocean droplet),可用性为  98.10% ,13.200 次请求中失败251 次 (与数据库的连接失败几次)。

第 34 段(可获 0.95 积分)

使用 Siege 发送数据

到目前为止,我们仅发送 HTTP GET 请求,通常这足够获得应用性能的概貌。通常在负载测试中发送数据也是合理的(例如,测试 API 端点)。使用 Siege,你可以很容易地向你的端点发送数据。

siege --reps=1 -c 1 'http://sfdemo.loc POST foo=bar&baz=bash'

你也可以使用 JSON 格式发送数据。通过使用 --content-type 参数,我们可以指定请求的内容类型。

siege --reps=1 -c 1 --content-type="application/json" 'http://sfdemo.loc POST {"foo":"bar","baz":"bash"}'
第 35 段(可获 0.91 积分)

我们也可以使用 --user-agent="MY USER AGENT" 来修改默认的 user agent 或是使用 --header="MY HEADER VALUE" 来指定多个 HTTP 头部。

Siege 也可以由文件读取负载数据:

cat payload.json
{
  "foo":"bar",
  "baz":"bash"
}

siege --reps=1 -c 1 --content-type="application/json" 'http://sfdemo.loc POST < payload.json'

你可以通过使用 --header 选项在测试中发送 cookie:

siege --reps=1 -c 1 --content-type="application/json" --header="Cookie: my_cookie=abc123" 'http://sfdemo.loc POST < payload.json'

结论

当需要对 web 应用进行负载,压力与回归测试时,Siege 是一个强大的工具。Siege 有许多选项,你可以用来使得你的测试行为尽可能接近真实环境,因而比起其他工具,例如 ab ,Siege 是我的首选工具。如果你希望更严格地测试你的应用,你可以组合 Siege 提供的不同选项,甚至是并行运行多个 Siege 进程。

第 36 段(可获 1.39 积分)

自动化测试过程(一个简单的 bash 脚本可以完成该工作)与可视化结果总是一个好主意。我通常依据真实的比率,以高频率并行运行多个 Siege 进程测试只读端点(例如,仅发送 GET 请求),以低频率发送数据(例如,发布评论,无效化缓存等)。因为你不能在一个 Siege 测试中指定动态负载,你可以在两个请求之间设置较大的延时并使用不同的参数运行更多的 Siege 命令。

同时我正在思考向我的 CI 管道添加简单的负载测试以确保对于重要的端点我的应用的性能不会低于可接受的水平。

我希望听到你的观点 - 你如测试你的应用的性能与稳定性?你有哪些建议与技巧?你认为我落下了什么吗?在下面留下你的评论!

第 37 段(可获 1.96 积分)

文章评论