这几天在做性能工具和平台的一些对比测试,其实按我们的需求量来讲,不存在啥特别大的压力,最多也不过百W级别的PV,但是我觉得既然我在架构组了,得找点更高级的事做一下吧。有跟几个领导讨论过,其中有个领导说:性能也就那么回事,现在就是要看怎么能快速便捷的操作,快速得出目标结果。
我觉得他讲的很有道理。
这一次分了2步,一步是流量统计的,这部分我提了需求给了运维同事帮忙我在运维平台实现,以后再讲了。另一步是我这边整合罗列了几个市面上比较常用且热门的开源工具,进行了测试,目前为止,除了loadrunner以外,ngrinder使用体验最好,说实话,我真是不喜欢jmeter的很,为啥很多测试人员一提性能工具就必须提jmeter,真的,我不喜欢用它的很。
开始正题,这2天对ngrinder毕竟感兴趣,上手研究了一下,也许是他的监控吸引了我,也许是他的横向扩容agent吧,总之,今天我总结一下,接下来继续再用用。
简介
nGrinder是一个用于在多台机器上运行用jython、groovy(在JVM上运行的)编写的测试脚本的应用程序。它的内部引擎是基于Grinder。nGrinder分别用控制器和agent将Grinder的控制台和agent包装起来,并扩展了支持多个并发测试的特性。
使用体会
- groovy脚本易用、易改、易维护
- 同等条件下与其它工具相对比,机器资源利用更充分
- 负载机可横向扩展agent,支持动态Agent分派
- 压测及监控一体,图表形式更直观,可自定义扩展监控项
使用
-
agent安装-负载机,解压启动:
nohup run_agent.sh &
-
moniter安装-应用服务器、数据库服务器,解压启动:
nohup run_monitor.sh &
-
访问:http://192.168.52.118:8080/ admin/admin登陆
-
添加脚本
测试URL
多参:http://192.168.52.116:8001/login?username=lisi&password=123456
简易:http://192.168.52.116/info/1.txt
5. 场景设置
选择agent、设置虚拟用户数、选择脚本、测试时长、测试次数。。
6.结果查看
本地调试
新建脚本选择groovy Maven Project,创建成功后,会有SVN地址可在IDE中checkout,使用ngrinder-controller登陆用户和密码
本地这样的目录结构
动态取参示例
@RunWith(GrinderRunner)
class PostBodyRunner {
public static GTest test
public static HTTPRequest request
public static NVPair[] headers = []
public static NVPair[] params = []
public static Cookie[] cookies = []
public static List<String> LineList
public static String body
@BeforeProcess
public static void beforeProcess() {
HTTPPluginControl.getConnectionDefaults().timeout = 6000
test = new GTest(1, "192.168.8.32:9200")
List<NVPair> headerList = new ArrayList<NVPair>()
headerList.add(new NVPair("Content-Type", "application/json"))
headerList.add(new NVPair("charset", "UTF-8"))
headers = headerList.toArray()
request = new HTTPRequest()
LineList=new File("./resources/resource2.txt").readLines("GB2312") //获取参数
grinder.logger.info("before process.");
}
@BeforeThread
public void beforeThread() {
test.record(this, "test")
grinder.statistics.delayReports=true;
grinder.logger.info("before thread.");
}
@Before
public void before() {
request.setHeaders(headers)
cookies.each { CookieModule.addCookie(it, HTTPPluginControl.getThreadHTTPClientContext()) }
/*//获取参数
rowNumber = new Random().nextInt(paramslist.size())
grinder.logger.info("rownum=="+rowNumber)*/
grinder.logger.info("before. init headers and cookies");
}
@Test
public void test(){
body = LineList.get(grinder.threadNumber).toString()
HTTPResponse result = request.POST("http://192.168.8.32:9200/pconline_itbbs_not_text/_search", body.getBytes())
if (result.statusCode == 301 || result.statusCode == 302) {
grinder.logger.info("Warning. The response may not be correct. The response code was {}.", result.statusCode)
} else {
assertThat(result.statusCode, is(200));
assertThat(result.getText(), containsString("id"))
}
}
}
多action请求
@RunWith(GrinderRunner)
class MultiRunner {
public static GTest test1
public static GTest test2
public static HTTPRequest request1
public static HTTPRequest request2
public static NVPair[] headers = []
public static NVPair[] params = []
public static Cookie[] cookies = []
public static List<String> LineList
@BeforeProcess
public static void beforeProcess() {
HTTPPluginControl.getConnectionDefaults().timeout = 6000
test1 = new GTest(1, "192.168.52.116")
test2 = new GTest(2, "192.168.52.116")
request1 = new HTTPRequest()
request2 = new HTTPRequest()
LineList=new File("./resources/resource1.txt").readLines("GB2312") //获取参数
grinder.logger.info("before process.");
}
@BeforeThread
public void beforeThread() {
test1.record(this, "test1")
test2.record(this, "test2")
grinder.statistics.delayReports=true;
grinder.logger.info("before thread.");
}
@Before
public void before() {
request.setHeaders(headers)
cookies.each { CookieModule.addCookie(it, HTTPPluginControl.getThreadHTTPClientContext()) }
/*//获取参数
rowNumber = new Random().nextInt(paramslist.size())
grinder.logger.info("rownum=="+rowNumber)*/
grinder.logger.info("before. init headers and cookies");
}
@Test
public void test1(){
List<NVPair> paramList = new ArrayList<>()
paramList.add(new NVPair("username",(LineList.get(grinder.threadNumber).toString().split(","))[0]))
paramList.add(new NVPair("password",(LineList.get(grinder.threadNumber).toString().split(","))[1]))
params = paramList.toArray()
HTTPResponse result = request1.GET("http://192.168.52.116:8001/login", params)
if (result.statusCode == 301 || result.statusCode == 302) {
grinder.logger.info("Warning. The response may not be correct. The response code was {}.", result.statusCode)
} else {
assertThat(result.statusCode, is(200));
assertThat(result.getText(), containsString("id"))
}
}
@Test
public void test2(){
List<NVPair> paramList = new ArrayList<>()
paramList.add(new NVPair("username",(LineList.get(grinder.threadNumber).toString().split(","))[0]))
paramList.add(new NVPair("password",(LineList.get(grinder.threadNumber).toString().split(","))[1]))
params = paramList.toArray()
HTTPResponse result = request2.POST("http://192.168.52.116:8001/login", params)
if (result.statusCode == 301 || result.statusCode == 302) {
grinder.logger.info("Warning. The response may not be correct. The response code was {}.", result.statusCode)
} else {
assertThat(result.statusCode, is(200));
assertThat(result.getText(), containsString("id"))
}
}
}
总结:简单使用,网上资料很多,实操还是会遇到一些问题,解决后,就知道其中的大概原理了。