51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

查看: 2171|回复: 4
打印 上一主题 下一主题

[测试工具] 基于线上请求的性能测试系统 CPC

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2017-8-9 10:51:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 八戒你干嘛 于 2017-8-9 10:54 编辑

1.背景

测试人员在设计性能测试脚本时,HTTP请求中的参数往往根据个人经验设置,而测试人员水平参差不齐,设计往往具有局限性,不够全面,不能涵盖全线上真实的请求,故得到的性能测试结果不能够真实反映线上真实的情况。

使用线上环境下的HTTP请求检查软件性能的问题,通过Gor记录线上真实的请求,作为性能测试脚本的请求池,用请求池物料进行性能测试,能真实的反映软件系统在线上环境下的性能指标和问题。

2.概念2-1.架构图


2-2.技术栈请求池:

Gor:

HTTP 录制工具https://github.com/buger/gor

Webdis:

A very simple web server providing an HTTP interface to Redis https://github.com/nicolasff/webdis

redis:

持久化缓存

性能测试工具:

nGrinder二次开发:

http://blog.csdn.net/neven7/article/details/50740018

Spring MVC

链路可视化:

watchman(微博APM)

influxDB:

时序化DBhttps://github.com/influxdata/influxdb

Grafana:

可视化工具]https://github.com/grafana/grafana

3.实现3-1.请求池

使用Gor录制线上请求,根据线上请求,序列化成Json String, 持久化到redis;性能测试脚本根据key,获取到线上请求数据,进行压测。

为了方便部署请求池,将请求池docker化,使用如下命名,启动docker容器:

  1. docker run -i -t --net=host gor-request-parser /bin/bash
复制代码

开始录制线上数据:

  1. sh gor_request_parser.sh 8080 60 GET your_api_name NONBASIC ip port

  2. 参数介绍:
  3. 8080:监听端口
  4. 60:监听时间(秒)
  5. GET:HTTP METHOD
  6. your_api_name:过滤其他url,只保留your_api_name请求
  7. NONBASIC:非BASIC认证接口,参数BASIC为BASIC接口
  8. ip port:webdis服务
复制代码

60s后, 请求数据持久化到redis中

  1. ***************************************************
  2.               gor http请求 序列化                  
  3.   http请求记录中,60 秒后,终止记录   
  4. ***************************************************
  5. Version:

  6. ***************************************************
  7.        记录结束, http请求序列化到请求池     
  8.        @author hugang      
  9. ***************************************************
复制代码

redis的key为$date_$hostname_$url

value为Json Array,形如:




3-2.性能测试脚本

性能测试工具使用nGrinder,进行二次开发,请参考:http://blog.csdn.net/neven7/article/details/50740018
性能测试脚本使用redis获取线上请求数据,依赖jedis、fastJson,在脚本lib中导入这2个jar包。

范例:

  1. package org.ngrinder;

  2. import static net.grinder.script.Grinder.grinder
  3. import static org.junit.Assert.*
  4. import static org.hamcrest.Matchers.*
  5. import net.grinder.plugin.http.HTTPRequest
  6. import net.grinder.plugin.http.HTTPPluginControl;
  7. import net.grinder.script.GTest
  8. import net.grinder.script.Grinder
  9. import net.grinder.scriptengine.groovy.junit.GrinderRunner
  10. import net.grinder.scriptengine.groovy.junit.annotation.BeforeProcess
  11. import net.grinder.scriptengine.groovy.junit.annotation.BeforeThread
  12. // import static net.grinder.util.GrinderUtils.* // You can use this if you're using nGrinder after 3.2.3
  13. import org.junit.Before
  14. import org.junit.BeforeClass
  15. import org.junit.Test
  16. import org.junit.runner.RunWith

  17. import HTTPClient.HTTPResponse
  18. import HTTPClient.NVPair


  19. import java.util.ArrayList;
  20. import java.util.Collections;
  21. import java.util.List;

  22. import groovy.json.JsonBuilder
  23. import groovy.json.JsonSlurper

  24. import com.alibaba.fastjson.JSONArray;
  25. import redis.clients.jedis.Jedis;

  26. /**
  27. * A simple example using the HTTP plugin that shows the retrieval of a
  28. * single page via HTTP.
  29. *
  30. * This script is automatically generated by ngrinder.
  31. *
  32. * @author hugang
  33. */
  34. @RunWith(GrinderRunner)
  35. class TestRunner {
  36.     public static GTest test
  37.     public static HTTPRequest request
  38.     public static File file
  39.     public static JSONArray jsonArray

  40.     @BeforeProcess
  41.     public static void beforeProcess() {
  42.         HTTPPluginControl.getConnectionDefaults().timeout = 6000
  43.         test = new GTest(1, "压测ip")
  44.         request = new HTTPRequest()
  45.         test.record(request);

  46.         // 读取请求池数据
  47.         Jedis jedis = new Jedis("redis ip", redis port);
  48.         // redis key
  49.         String key = "your key";
  50.         String jsonStr = jedis.get(key);

  51.         jsonArray = JSONArray.parseArray(jsonStr);
  52.         // grinder.logger.info(jsonArray.getString(0));
  53.         // grinder.logger.info("before process.");
  54.     }

  55.     @BeforeThread
  56.     public void beforeThread() {
  57.         grinder.statistics.delayReports=true;
  58.     }


  59.     @Test
  60.     public void test(){
  61.         // 随机获取
  62.         int index = (int) (Math.random() * jsonArray.size());
  63.         String httpInfo = jsonArray.getString(index);


  64.         def json = new JsonSlurper().parseText(httpInfo)

  65.         String api = json.api
  66.         Map param = json.param

  67.         def nvs = []
  68.         param.each{
  69.             key, value -> nvs.add(new NVPair(key, value))
  70.         }


  71.         // GET请求,wiki http://grinder.sourceforge.net/g3/script-javadoc/net/grinder/plugin/http/HTTPRequest.html
  72.         // param1: uri, param2: queryData
  73.         // HTTPResponse GET(java.lang.String uri, NVPair[] queryData) Makes an HTTP GET request.
  74.         HTTPResponse result = request.GET("http://压测ip" + api, nvs as NVPair[])
  75.         if (result.statusCode == 301 || result.statusCode == 302) {
  76.             grinder.logger.warn("Warning. The response may not be correct. The response code was {}.", result.statusCode);
  77.         } else {
  78.             assertThat(result.statusCode, is(200));
  79.             // 请求返回的数据
  80.             // println(result.text);
  81.             // 定义一个事务,接口返回数据校验,是否包含
  82.             assertThat(result.text, containsString("\"code\""));
  83.         }
  84.     }
  85. }
复制代码
3-3. 链路时间分布可视化

链路时间展示,启动web服务指定-javaagent为watchman agent,使用字节码增强,获取某一段时间内代码链路的分布时间。
请参考:http://blog.csdn.net/neven7/article/details/50980726


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
回复

使用道具 举报

该用户从未签到

2#
发表于 2017-8-9 14:23:34 | 只看该作者
其实这思路就是将线上的真实请求在测试环境回放吧
回复 支持 反对

使用道具 举报

该用户从未签到

3#
 楼主| 发表于 2017-8-9 14:27:43 | 只看该作者
巴黎的灯光下 发表于 2017-8-9 14:23
其实这思路就是将线上的真实请求在测试环境回放吧

角度不一样,直接流量回放是粗粒度的,性能数据不好统计,我们这边也有,是使用TCPCopy直接放大线上流量(开发和运维操作),一般通过监控系统观察错误和响应时间或者通过代码打点统计日志数据;CPC是细粒度的,性能测试脚本直接通过线上的请求数据压测,通过不同的qps模拟正常流量和峰值流量下各项性能指标。
回复 支持 反对

使用道具 举报

该用户从未签到

4#
发表于 2017-8-9 14:33:09 | 只看该作者
这个工具性能怎么样?如果要支持百万级的下单借口,需要多少负载机啊?
回复 支持 反对

使用道具 举报

该用户从未签到

5#
 楼主| 发表于 2017-8-9 14:55:17 | 只看该作者
乐哈哈yoyo 发表于 2017-8-9 14:33
这个工具性能怎么样?如果要支持百万级的下单借口,需要多少负载机啊?

性能还是可以的,当然nGrinder工具本身是用java写的,并发量很高时是很耗内存,这就要求安装的机器配置要很高;启web容器时,堆的大小也要尽量大点,单个nGrinder controller万级是可以支持的(实践已经到了万级),如果搭建controller集群几十万级的量还是可以(理论,没校验);百万级的,我所了解,业内还没有这种工具;你如果只是想得出接口性能数据,其实不一定要模拟到百万级,你算出均摊到单台前端机的qps,直接压测单台。接口日均pv * (80%/20%)/(24 * 3600)/前端机总数=单台前端qps峰值
回复 支持 反对

使用道具 举报

本版积分规则

关闭

站长推荐上一条 /1 下一条

小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

GMT+8, 2024-4-26 12:57 , Processed in 0.065731 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2024 Comsenz Inc.

快速回复 返回顶部 返回列表