查看原文
其他

详解站点压测利器——nGrinder

胡晔 陈美玲 58技术 2022-03-15


导语

本文主要介绍nGrinder这款强大的压测工具,一起了解下它的架构原理、环境搭建和压测流程,为我们提供稳定易扩展的分布式压测环境。希望对大家有所帮助和启发。


背景

用户访问量不断增长的同时,也伴随着后台站点性能要求的不断提升。很多情况下流量成倍增长所需的机器资源并不是简单的线性增加,更可能会成几何倍数飙涨,这不仅需要我们做好站点的诸如过载保护、主备冗余等容灾方案,更需要通过压测来提前查找系统性能瓶颈点和吞吐量上限,再根据预估流量进行提前扩容,避免流量高峰出现不必要的大量请求丢弃。那么对线上站点进行模拟压测,将是我们预估站点请求的最大承载量,估算业务站点所需机器资源等的有效手段。

下面将主要介绍nGrinder这款强大的压测工具,一起了解下它的原理特点、环境搭建步骤和压测流程,为我们提供稳定易扩展的分布式压测环境。


站点压测利器——nGrinder

1.  nGrinder&jmeter对比

jmeter是一款大家熟知的压测软件,它是apache组织开发的一款基于java的压测软件,而nGrinder所为一款分布式高并发开源压测软件,是由NHN公司基于Grinder开源项目所做的二次开发,那么nGrinder与Jemter之间的对比有什么不同呢?





从上图可以看出,nGriner在综合性能监控、并发数、稳定性和分布式扩展等方面相比jmeter&Gatling具有不同程度的优势,当然这依赖于开发人员通过对压测脚本等进行二次开发的方式,提升整个压测平台的灵活稳定性等。下面将详细介绍nGrinder基本原理、环境搭建和压测流程。

2.  nGrinder整体架构

nGrinde压测框架核心由controller和agent两个组件组成,其中controller负责管理和控制测试流程(web管理后台)、下发测试任务&脚本文件到agent端以及查看测试监控报告等。agent负责启动压测进程&线程,压测目标服务器,并在测试完成后归还agent给AgentManager管理,还可以监控目标服务器&被压测站点各项性能指标(基于jmx)。

使用nGrinder开启一个压测任务前,首先需要部署controller和多个agent端,agent端在启动后会链接到controller内的AgentManager(Agent管理池)。之后需要我们通过controller端的web管理界面来创建压测脚本和测试任务,这时我们就可以执行已创建好的压测任务了。整体执行流程如下:

  • 当压测任务启动后,nGrinder首先会创建一个nGrinder Console;

  • 已创建完成的nGrinder Console会向AgentManager申请本次压测任务所需数量的agent;

  • nGrinder Console会向申请到的agent派发本次压测任务所需的脚本、资源文件等内容;

  • 资源分发完毕后,nGrinder Console会控制agent执行测试流程(按照压测任务中配置多个进程和线程来读取资源文件&并发执行压测脚本,模拟多用户(vuser)并发压测站点),直到本次测试结束;

最后我们还可以在controller管理后台查看测试报告&借助Monitor组件监控系统性能指标。

nGrinder的整体结构图如下:






3. 环境搭建

3.1 下载nGrinder

下载地址:https://github.com/naver/ngrinder/releases选择最新版本ngrinder-3.4(即grinder-controller-3.4.war)

3.2 使用tomcat启动controller

3.4版本ngrinder支持在jdk1.8环境下运行,使用tomcat8.0版本部署即可,将grinder-controller-3.4.war放置在tomcat容器的/webApps文件夹中 ,或将文件按独立web工程解压,部署在如/opt/web/ngrinder/webapps目录下。成功启动后,访问站点ip+端口号,进入登陆页面,如下图所示:





3.3 agent安装

Controller安装完成后,登陆管理后台站点,点击顶部右侧下拉菜单中的Download Agent进行下载。

将下载好的ngrinder-agent-3.4.tar直接解压,执行目录下的sh run_agent.sh & 命令即完成agent启动。如果需要停止agent,执行stop_agent.sh。启动agent.sh后,可以点击右上角菜单中的Agents Management选项进入agents管理页面。





 PS:agent支持横向扩展,我们需要根据被压测站点规模,合理评估agent节点所需部署数量。

3.4 安装monitor

        1> 点击右上角菜单中的Download Monitor选项





       2> 下载monitor,将monitor安装包解压在被压测机器。执行目录下的启动命令:sh run_monitor.sh即可

        3> 至此压测环境基本搭建完成,通过管理后台即可查看部署的agent和monitor节点是否和controller端连接成功。

需要注意的是:请勿将agent和被压测站点部署在同一台机器上(会严重影响被压测站点性能,争抢cpu、内存等机器资源)。monitor节点需要和被压测站点部署在同一台机器上。

 

4.  编写压测脚本

4.1 简易创建压测脚本

压测站点前,首先需要编写压测脚本。通过点击管理后台上方的script按钮,进入脚本管理页面,即可创建。(在首页quick start输入框中输入目标url也可直接创建脚本,效果相同)







在管理后台创建一个脚本时,首先需选择脚本语言(支持Groovy & Jython),填写脚本名,再选择get或post方法访问测试url,之后需要添加url以及请求所需要的其他额外参数(header、cookie、params),选择填写页如下图所示:




PS:官方考虑到Groovy和Jython两种语言执行性能上的差别,建议优先使用性能更好的Groovy来编写压测脚本(通过对两种语言for循环10W以上执行时间比较,耗时相差在20倍左右),下图是生成的Groovy脚本页面:




由于Groovy和java之间具有极高的兼容性,很多jdk类库可直接调用,很容易上手编写,对应java开发人员来说,学习成本很小。

4.2 使用脚本模拟真实稳定压测环境

通常线上web或者服务站点出于性能优化考量,针对各业务场景都大量使用到缓存,导致压测数据相同时,每次命中缓存后快速响应请求,造成站点压测性能极佳的假象(但线上真实请求参数各异)。所有站点做压测时,更希望让每个压测请求都携带不同的线上请求参数,为了满足模拟真实压测环境要求,就需要我们在脚本开发时做如下准备

        1> 准备线上真实环境下各种参数形式的压测数据

        2> 让每个压测线程,每次访问目标服务器时,分别携带不同的请求参数

        3> 控制单个压测线程的单次执行时间,保证各线程能以稳定速率向目标服务器发送请求

        4> 脚本是否能通过传参灵活控制内部逻辑

上述几个要求,是我们接下来重点考虑的问题

        4.2.1  压测数据准备:以压测web站点为例,我们可以利用tomcat开启的access日志来收集线上真实请求数据(nginx的线上访问日志同样满足),将打印在access日志中的正常格式请求过滤出来,整理成压测数据文件。如果压测的是单台机器,还需要将数据中的域名替换为ip+端口形式,留待压测时使用。下图所示是某线上站点的请求数据:





注意:当压测依赖下游服务,尤其是其他部门站点时,需要评估对依赖方的影响并予以周知,避免压测数据影响线上业务&统计分析等

        4.2.2 各压测线程读取不同数据:由于nGrinder是分布式压测工具,在向每个agent节点下发的测试数据文件都是相同的,这就需要我们在脚本中指定不同的数据文件片段供各线程分别读取。nGrinder为了方便我们让每个线程执行不同的业务逻辑,内置了ScriptContext上下文容器对象,供我们获取当前脚本运行环境下的常用参数,如下图所示:





由于脚本容器在启动时已将所有的agent、进程和线程进行了编号,从0到该类型节点在配置项中的最大值-1。例如当我们使用1个agent节点下配置10个process,每个process下配置100个线程来运行脚本,此时当前线程内获取到的grinder.processNumber值是0到9中的某一个,grinder.threadNumber线程值是0到99中的某一个,这样我们便可以先将整个数据文件按总agent、总进程和总线程数做数据切割,再根据当前线程所对应的进程、线程编号,读取对应的压测数据。如下是在进程初始化时,单个agent下对多进程、多线程压测数据文件切割示例:可先通过如下代码筛选出当前进程可读取的数据片段范围,后续线程执行时,再根据当前线程编号获取各自线程的数据片段,按顺序读取即可:





     4.2.3脚本控制稳定的TPS:由于ngrinder在执行压测任务时,所有启动线程都在循环重复执行脚本,每次请求发送响应时间都是不同的,这种情况下单位时间内单个线程的执行次数是不可控的,TPS会随平均响应时间变慢而下降,无法维持稳定的TPS压测环境。针对这种情况,我们可以在压测脚本中增加Thread.sleep方法,控制单次脚本执行耗时,当并发执行该脚本时,使执行脚本的线程以稳定的时间间隔执行,产生稳定的TPS。





上图所示等待时间,为1秒减去当前请求耗时(等待时间=单位时间1秒 -当前请求执行耗时,这样用Thread.sleep(等待时间) 方法来控制等待时间,保证每个单位时间周期内,都能稳定发出一次请求,从编码上保证TPS的稳定性),当压测目标站点平均响应时间很长时(如平均超过1秒占比较大),可自行调整等待总时间到2000ms甚至更高的毫秒数,通过脚本逻辑保证单个线程产生的TPS是稳定的。

        4.2.4 脚本传参方式:通过前面的介绍,了解到控制压测请求TPS需要获取整个环境下的总agent数、进程数和线程数,通过写死当前压测任务下的这些数值会使得每次调整压测Tps时都要去修改脚本,而nGrinder提供了脚本输入参数配置项,我们可以自定义输入配置来传递当前压测任务的总进程、线程数,脚本中使用System.getProperty("param")方法即可获取到输入参数:





PS:在调整参数过程中,如果所准备的压测数据过大时,建议增大进程数,从而减小单个进程所需提取的压测数据段大小,减少初始化时间。


5. 执行压测任务

5. 1 选择主页上面的Performance Test选项,进入性能测试列表页中,点击create Test创建压测任务,如下图所示:









在配置压测环境时,需要遵循如下规定

        1> 配置项中的vuser虚拟用户数量直接对应脚本单位时间内的并发执行次数TPS(TPS = 执行请求数量 / 单位时间(秒)),也可通过设置进程、线程数量让平台自动计算所需初始化的进程&线程数,对应关系为vuser数= procsses数 * Thread数。(设置vuser数 或processes + Thread数 两种配置并发效果相同)

        2> 单个procsses配置的线程数请勿超过200,单个agent支持的总vuser数建议不要超过5000,且保证单个agent运行至少有双核、6G空闲内存可使用(单agent并发量越高,所需内存越大)

        3> 当被压集群qbs大于3000时,建议启动多个agent来分摊压测进程,来保证压测性能稳定性

        4> 使用配置项paramter可向压测脚本中传入自定义参数,(如传入进程&线程数,来切分压测数据,让每个线程读取不同的压测数据,达到模拟线上真实请求的目的) 

5.2 配置好压测任务后即可立刻执行压测任务(平台也提供了延迟执行压测任务功能)压测执行结果如下图所示:





我们可以看到,通过脚本内部控制单次请求执行&等待时间,使得整个压测任务在启动后TPS都较为平稳,我们还可以通过查看压测日志文件&详细压测报告(含CSV表格,如下图所示),观察整个压测过程中站点响应时间变化、机器性能状况(需要被压测机安装monitor)等。






6. 扩展功能介绍

6.1 支持依赖第三方包 & 压测数据文件获取:

nGrinder支持上传压测数据文件 & 第三方类库jar包,灵活支持自定义脚本的扩展性,只需在lib和resource目录中上传依赖的数据文件和jar包,在脚本里用使用相对路径配置对应目录即可,上传位置如下图所示:






6.2 自定义数据视图:

我们在使用nGrinder配置脚本压测时,除了观察基本的Tps、平均响应时间、机器cpu、内存等性能指标时,还可以通过压测脚本收集数据,展示在自定义视图上(只支持展示一种自定义数据),我们可以在脚本初始化时,使用grinder.statistics.registerSummaryExpression(java.lang.StringdisplayName, java.lang.String expression) 方法定义传入数据计算表达式,将每个线程执行时收集到的数据传入grinder.statistics.forLastTest方法中,最终汇总到controller端展示在最后的详细报告中。

下图是用自定义方法收集到的脚本逻辑平均耗时图:






总结、展望或规划

通过本文介绍,我们能看到nGrinder是一款性能稳定可扩展灵活的分布式压测工具,当然,这依赖于开发人员在压测脚本等所做的二次开发编码,我们可使用更贴近java语法的Groovy语言编码来降低我们的语言学习成本,更快速的编写出灵活通用的压测脚本,满足我们对站点吞吐量的准确评估需求,更好的规划线上站点的机器数配比,平稳度过全年流量高峰期。


参考文献

1.     官网资料地址:

https://github.com/naver/ngrinder/releases

2.     api接口文档:

http://grinder.sourceforge.net/g3/script-javadoc/index.html?help-doc.html


作者简介

胡晔 / 58同城招聘技术部-主站与基础架构组 资深开发工程师,负责组内运营&seo、消息推送、电话保护、任务管理平台等业务与基础组件开发&维护。

END

阅读推荐
开源|Magpie:Magpie在安居客有料业务的落地实践
开源|Magpie:混合开发工程化框架
Go服务在容器内CPU使用率异常问题排查手记
开源|Magpie:平台工具链开发实践
开源|Magpie:58 跨平台技术应用及 Flutter 实践概览

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存