先观察下面截图,可以看到两个关键信息:
这台机器已经建立了 238 万个 TCP 连接
使用内存大约在 48G。
下面将会介绍在单个 HAProxy 机器上实现这种规模访问所需的配置。本文是负载测试 HAProxy 系列文章的最后一篇。有时间的读者建议阅读本系列的前两篇(见文末链接),它将帮助您了解相应的内核调优方法。
在这个配置过程中,我们也使用了很多小组件帮助我们达到目标。
在展开最终 HAProxy 配置之前,我想给大家回顾一下负载测试的历程及想法,心急的读者可以直接跳到文章后段查阅相关 HAProxy 配置。
我们要测试的组件是 HAProxy 1.6 版。生产环境是在 4 核 30 G 的机器上运行该软件,当前所有的连接都是非 SSL 的。
测试目标有两方面:
当将整个负载从非 SSL 连接转移到 SSL 连接时,CPU 使用率增加的百分比。CPU 的使用率肯定会增加,这是由于 5 次握手的加长和数据包加密的开销所带来。
其次,希望能够测试单个 HAProxy 每秒请求数和最大并发连接数的上限
目标一主要因为业务方面功能需要通过 SSL 进行通信。 目标二是为了可以在生产环境中部署最少规模的 HAProxy 机器。
使用多台客户端机器来执行 HAProxy 压力测试。
有各种配置的 HAProxy 1.6 的机器
4核,30G
16核,30G
16核,64G
相关后端服务器,用于支持所有并发访问。
我们的整个基础设施支持两种协议:
HTTP
MQTT
在我们的技术栈中,没有使用 HTTP 2.0,因此在 HTTP 上没有长连的功能。所以在生产环境中,单个 HAProxy 机器(上行 + 下行)的最大数量的 TCP 连接在(2 * 150k)左右。虽然并发连接数量相当低,但每秒请求的数量却相当高。
另一方面,MQTT 是一种不同的通信方式。它提供高质量的服务参数和持久的连接性。因此,可以在 MQTT 通道上使用双向长连通信。对于支持 MQTT(底层 TCP)连接的 HAProxy,在高峰时段会看到每台机器上大约有 600 - 700k 个 TCP 连接。
我们希望进行负载测试,这将为我们提供基于 HTTP 和 MQTT 连接的精确结果。
有很多工具可以帮助我们轻松地测试 HTTP 服务器,并且提供了高级功能,如结果汇总,将文本转换为图形等。然而,针对 MQTT,我们找不到任何压力测试工具。我们确实有一个自己开发的工具,但是它不够稳定,不足以支持这种负载。
所以我们决定使用客户端测试 HTTP 负载,并在 MQTT 服务器使用相同配置。
考虑到相关内容对于进行类似的压力测试或调优的人来说有帮助,本文提供了很多相关细节,篇幅稍微有些长。
我们采用了一台 16 核 30G 机器来运行 HAProxy,考虑到 HAProxy 的 SSL 产生的 CPU 巨大开销,因此没有直接使用目前生产环境。
对于服务器端,我们使用了一个简单的 NodeJs 服务器,它在接收到 ping 请求时用 pong 进行回复。
对于客户端,我们最终使用 Apache Bench。使用 ab 的原因是因为它是一个大家熟悉和稳定的负载测试工具,它也提供了很好的测试结果汇总,这正是我们所需要的。
ab 工具提供了许多有用的参数用于我们的负载测试,如:
-c,指定访问服务器的并发请求数。
-n,顾名思义,指定当前负载运行的请求总数。
-p,包含 POST 请求的正文(要测试的内容)。
如果仔细观察这些参数,您会发现通过调整所有这三个参数可以进行很多排列组合。示例 ab 请求将看起来像这样
ab -S -p post_smaller.txt -T application/json -q -n 100000 -c 3000 http://test.haproxy.in:80/ping
这样的请求的示例结果看起来像这样
我们感兴趣的数字是:
99% 的返回请求的响应延迟时间。
Time per request:每个请求的时间
No. of failed requests:失败请求数。
Requests per second: 每秒请求量
ab 的最大问题是它不提供控制每秒发起请求量,因此我们不得不调整 -c 并发级别以获得所需的每秒钟请求数,并导致很多后文提到的问题和错误。
我们不能随机地进行多次测试来获得结果,这不会给我们提供任何有意义的信息。我们必须以某种具体的方式执行这些测试,以便从中获得有意义的结果。来看看这个图。
该图表明,在某一点之前,如果不断增加请求数量,延迟将几乎保持不变。然而,达到某个临界点,延迟将开始呈指数级增长。这就是该机器的临界点。
在提供一些测试结果之前,我想提一下 Ganglia。
Ganglia 是用于高性能计算系统(如集群和网格)的可扩展分布式监控系统。
看看截图,了解 Ganglia 是什么,以及它提供的关于底层机器的信息。
通过 Ganglia 可以监测 HAProxy 机器上一些重要参数。
TCP established 这告诉我们在系统上建立的 TCP 连接总数。注意:这是上行和下行连接的总和。
packets sent and received 发送和接收的 TCP 数据包的总数。
bytes sent and received 这将显示发送和接收的字节数。
memory 随着时间的推移使用的内存数。
network 通过线路发送数据包而消耗的网络带宽。
以下是通过通过负载测试找到的已知限制。
700k TCP 连接,
50k 发送包数量,60k 接收包数量,
10-15MB 发送及接收的字节数,
14-15G 内存峰值,
7MB 带宽。
所有这些值都是基于每秒数据
最初,当我们开始测试 HAProxy 时,发现使用 SSL 情况下,CPU 很早就到了瓶颈,而每秒请求数都很低。 在使用 top 命令后,发现 HAProxy 只使用 1 个 CPU 核。 而我们还有 15 个以上的核没用。
Google 了 10 分钟后,我们在 HAProxy 中找到某个设置,可以让 HAProxy 使用多个核。
它被称为 nbproc,具体设置请看这篇文章 [8]:
调整此设置是我们的负载测试策略的基础。 让我们可以方面的进行 HAProxy 组合以便测试。
当开始负载测试之旅时,我们不清楚应该测量的指标和需要达到的目标。
最初,我们只有一个目标:通过改变所有下面提到的参数来找到临界点。
我保留了各种负载测试结果的表格。 总而言之,做了 500 多次测试,以达到最终的效果。 您可以清楚地看到,每次测试都有很多不同的部分。
我们看到客户端正在成为瓶颈,因为我们不断增加每秒的请求数。 ab 使用单个核,从文档中可以看出,它不提供使用多核的功能。
为了有效地运行多个客户端,我们发现一个有用的 Linux 工具叫做 Parallel [7]。 顾名思义,它可以帮助您同时运行多个命令来达到并行的目的。 正是我们想要的。
看一下使用 Parallel 运行多个客户端的示例命令。
上述命令将运行 3 个 ab 客户端击访问同一个 URL。 这有助于我们消除客户端瓶颈。
下面是 Ganglia 中的一些参数。让我们简单讨论一下。
packets sent and received 为了产生更多数据,可以在 post 请求中添加更多数据
tcp_established 这是想实现的目标。想象一下,如果单个 ping 请求大约需要一秒钟,那么每秒需要大约 700k 个请求来达到 tcp_established 的目标。现在这个数字在生产环境中可能看起来更容易达到,但是在测试场景中不太可能达到。
我们在 POST 调用中加入了一个 sleep 参数,它指定了服务端发送返回之前需要 sleep 的毫秒数。这将模拟长时间运行的生产环境请求。如果让请求 sleep 20 分钟的话,只需要每秒发出 583 个请求就能达到 700k 并发连接的标准。
此外,我们还在 POST 调用中引入了另一个参数: times。服务器在返回请求时应该在 TCP 连接上写入响应的指定次数,这有助于模拟更多的数据。
虽然使用 AB 也得到了不少测试结果,但同时也遇到了很多问题。我不会在这里提到所有问题,因为不是这篇文章重点(下面介绍另一个客户端)。
我们非常满意从 ab 上获得的结果,但是它不支持在一段时间内生成所需指定的 TCP 连接数。不知何故,我们设置的 sleep 参数在 ab 上无法生效。
虽然在一台机器上可以运行多个 ab 客户端并且可以用工具合并结果,但是在多台客户机上运行此设置对我们来说仍然是一件痛苦的事情。那时我还没有听说过 pdsh [4] 这个工具。
此外,我们也没有关注过超时的问题。在 HAProxy,ab 客户端和服务器上有一些默认的超时设置,我们完全忽略了这些。后文会讲到。
我们一开始就提到通过临界点图来检测系统的上限,但讲了这么多有点偏离了最主要目标。然而,要得到有意义的结果只能着眼于这一点。
使用 AB 碰到的一个问题是到了某个点 TCP 连接数不再增加。我们有大约 40 - 45 个客户端运行在 5 - 6 台客户端机上,但依然不能达到想要的规模。理论上,TCP 连接的数量应该随着 sleep 时间的增加而增加,但对我们来说并非如此。
因此我们需要寻找一个负载测试工具,这些工具需要具有更好的扩展性和更好的功能性,最终,我们找到了 Vegeta [6]。
从我的个人经验来看,我已经看到 Vegeta 具有极高的扩展性,与 ab 相比,它提供了更好的功能。 在我们的负载测试中,单个 Vegeta 客户端能够产生相当于 15 倍 ab 的吞吐量。
下面,我将提供使用 Vegeta 的负载测试结果。
首先,看看我们用来运行一个 Vegeta 客户端的命令。 进行测试的命令称为 attack:(酷吧?)
我们太喜欢 Vegeta 提供的参数了,来看看下面的一些参数。
-cpus = 32 指定此客户机要使用的 CPU 核数。 由于要生成的负载量,我们不得不将客户机扩展到 32 核 64G。 虽然上面的速度也不是特别高。 但是当有大量处于 sleep 状态的连接时,维持这些连接也会产生比较大的开销。
-duration = 10m 我想这是不言自明的。如果没有指定任何持续时间,测试将永远运行。
-rate = 2000 每秒请求的数量。
所以如上图所示,我们在一台 4 核机器上每秒达到了 32k 请求量。 如果你记得临界点图,在这种情况下,非 SSL 请求的临时点是 31.5k。
从负载测试中看更多的结果。
16k 的 SSL 连接也不错。 请注意,在我们的负载测试过程中,必须从头开始,因为我们采用了一个新的客户端,它给了我们比 ab 更好的结果。 所以不得不再来一遍。
CPU 核数的增加导致机器在未达到 CPU 限制前,每秒可以用的请求数增加。
如果将 CPU 核数从 8 个增加到 16 个,我们发现每秒的请求数量并没有大幅度增加。如果在生产环境中使用 8 核机器,那么我们不会分配所有的核给 HAProxy,或者是它的任何其他进程。 所以我们决定用 6 核机器进行一些测试,看看是否能得到可接受的数字。
结果还不错。
我们现在对负载测试结果非常满意。 然而,这并没有模拟真正的生产场景。 当我们引入 sleep,才开始模拟生产环境的情况。
echo "POST https://test.haproxy.in:443/ping" | vegeta -cpus=32 attack -duration=10m -header="sleep:1000" -body=post_smaller.txt-rate=2000 -workers=500 | tee reports.bin | vegeta report
因此,x 毫秒的随机 sleep 时间将导致服务器 sleep 时间为 0 < x < 1000 。 因此上述负载测试将给出平均 ≥ 500ms 的延迟。
最后一个单元格中的含义是 TCP established, Packets Rec, Packets Sent
从表中可以看到,6 核机器可以支持的最大请求量从 20k 减少到 8k。 显然,sleep 有其影响,影响的是 TCP 连接的数量。 然而这距离我们设定的 700K 目标还很远。
我们如何增加 TCP 连接的数量? 很简单,不断增大 sleep 时间,连接数应该上升。 我们一直增加 sleep 时间并在 60 秒的 sleep 时间停了下来。 这意味着大约 30 秒的平均延迟。
Vegeta 可以提供成功请求百分比的结果参数。 我们看到,在上述的 sleep 时间,只有 50% 的调用是成功的。 请看下面的结果。
我们达到了 400 万个 TCP 连接,在每秒 8k 请求和 60s 的 sleep 时间的情况下。 60000R 的 R 表示随机。
我们的第一个的发现是,在 Vegeta 中有一个默认的超时时间是 30 秒,这就解释了为什么 50% 的请求会失败。 所以我们在后续测试中将超时调整到 70 秒,并随着需求的变化而不断变化。
在客户端调整超时值之后,我们可以轻松地达到 700k 标准。 唯一的问题是这些不可持续,只是峰值的数据。 系统达到了 600k 或 700k 的峰值链接,但并没有坚持很长时间。
但是我们想要得到图上连接持续很久的效果
这显示了稳定保持 780k 连接的状态。如果仔细查看上面的统计信息,每秒的请求数量非常多。然而,在生产环境中,我们在单个 HAProxy 机器上的请求数量要少得多(约 300 个)。
我们确信,如果减少生产环境的 HAProxy 的数量(约 30 个,这意味着每秒 30 * 300〜9k 的连接),我们将会达到机器 TCP 连接限制,而不是 CPU。
所以我们决定实现每秒 900 个请求、30MB/s 的网络流量,以及 210 万 TCP 连接。我们选用这些数字,因为这将是单个生产环境 HAProxy 机器的 3 倍流量。
到目前为止,我们已经配置了 HAProxy 使用 6 核。我们只想测试 3 核,因为这是我们在我们的生产机器上使用的最简单的方法(如前所述,我们的生产机器是 4 核 30G,所以用 nbproc = 3 进行更改将是最简单的)。
里程碑 #2
现在我们对每秒请求的最大限制可以随机器不同而变化,所以我们只剩下一个任务,如上所述,实现 3 倍的生产负载:
每秒 900 个请求
建立了 210 万个 TCP 链接。
30 MB/s 网络。
在 220k 的测试环境下,我们再次陷入僵局。 无论客户机数量多少或睡眠时间多少,TCP 连接数似乎都停留在那里。
我们来看一些估算数据。 220k TCP 连接,每秒 900 个请求 = 110,000 / 900〜= 120 秒。达到了 110k,因为 220k 连接包括上行和下行。
当我们在 HAProxy 开启日志时,我们怀疑 2 分钟是系统某处的限制。 我们可以看到 120,000 ms 是日志中大量连接的总时间。
在进一步调查中,我们发现 NodeJs 的默认请求超时为 2 分钟。 瞧!
但我们的高兴显然很短暂,在 130 万,HAProxy 连接数突然下降到 0,并再次开始增长。我们很快检查了 dmesg 命令,里面可以查到 HAProxy 进程一些有用的内核信息。
基本上,HAProxy 进程已经耗尽内存。因此,我们决定增加机器内存,并将其转移到 nbproc = 3 的 16 核 64GB 的机器,经过调整,我们终于可以达到 240 万长连。
下面是正在使用的后端服务器代码。 我们还在服务器代码中使用 statsd 来获取客户端接收的每秒请求的统计数据。
我们还有一个小脚本运行多个服务器。 我们有 8 台机器,每台机器部署了 10 个后端服务。 我们真的认为有条件的话可以进行无限扩容进行压测。
对于客户端,每个 IP 有最大 63k TCP 连接的限制。 如果您不确定这个概念,请参阅本系列之前的文章。
所以为了实现 240 万个连接(双向,来自客户机的是 120 万),我们需要约 20 台机器。 我们在所有机器上运行 Vegeta 命令,甚至找到了一种方法来使用像 csshx [3] 这样的工具,但仍然需要合并所有的 Vegeta 客户端的结果。
查看下面的脚本。
Vegeta 提供了名为 pdsh [4] 的工具信息,可让您在多台计算机上同时运行命令。 此外,Vegeta 可以让我们将多个结果合并成一个,这就是我们想要的。
下面可能是很多读者最关心的,我们在测试中使用的 HAProxy 配置。 最重要的部分是 nbproc 和 maxconn 参数。 maxconn 设置 HAProxy 允许提供的最大 TCP 连接数(单向)。
对 maxconn 设置的更改导致 HAProxy 进程的 ulimit 增加。 看看下面
最大打开文件已增加到 400 万,因为 HAProxy 的最大连接数设置为 200 万。
参阅文章 [5] 获得更多 HAProxy 优化。
相关链接
系统一 https://medium.com/@sachinmalhotra/load-testing-haproxy-part-1-f7d64500b75d
系列二 https://medium.com/@sachinmalhotra/load-testing-haproxy-part-2-4c8677780df6
haproxy 配置: https://www.linangran.com/?p=547
Parallel: http://www.shakthimaan.com/posts/2014/11/27/gnu-parallel/news.html
nbproc setup: http://blog.onefellow.com/post/82478335338/haproxy-mapping-process-to-cpu-core-for-maximum
本文作者 Sachin Malhotra,由 Jesse 翻译,转载请注明出处,技术原创及架构实践文章,欢迎通过公众号菜单「联系我们」进行投稿。
高可用架构
改变互联网的构建方式
长按二维码 关注「高可用架构」公众号
原文来自:高可用架构
声明:所有来源为“聚合数据”的内容信息,未经本网许可,不得转载!如对内容有异议或投诉,请与我们联系。邮箱:marketing@think-land.com
通过企业关键词查询企业涉讼详情,如裁判文书、开庭公告、执行公告、失信公告、案件流程等等。
IP反查域名是通过IP查询相关联的域名信息的功能,它提供IP地址历史上绑定过的域名信息。
结合权威身份认证的精准人脸风险查询服务,提升人脸应用及身份认证生态的安全性。人脸风险情报库,覆盖范围广、准确性高,数据权威可靠。
全国城市和站点空气质量查询,污染物浓度及空气质量分指数、空气质量指数、首要污染物及空气质量级别、健康指引及建议采取的措施等。
输入手机号和拦截等级,查看是否是风险号码