51Testing软件测试论坛

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

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

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

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

[复制链接]
  • TA的每日心情
    无聊
    2024-9-19 09:07
  • 签到天数: 11 天

    连续签到: 2 天

    [LV.3]测试连长

    跳转到指定楼层
    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 | 只看该作者
    其实这思路就是将线上的真实请求在测试环境回放吧
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    2024-9-19 09:07
  • 签到天数: 11 天

    连续签到: 2 天

    [LV.3]测试连长

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

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

    使用道具 举报

  • TA的每日心情
    无聊
    2024-7-12 13:16
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]测试小兵

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

    使用道具 举报

  • TA的每日心情
    无聊
    2024-9-19 09:07
  • 签到天数: 11 天

    连续签到: 2 天

    [LV.3]测试连长

    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-11-9 10:38 , Processed in 0.066584 second(s), 22 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

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