前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >性能测试中标记每个请求

性能测试中标记每个请求

作者头像
FunTester
发布于 2020-01-17 01:58:35
发布于 2020-01-17 01:58:35
41300
代码可运行
举报
文章被收录于专栏:FunTesterFunTester
运行总次数:0
代码可运行

在做性能测试过程中,遇到一个棘手的问题,开发让我们复现几个请求时间较长的请求,他们看日志进行链路追踪,查找瓶颈所在。

这里说一下框架中的处理逻辑:每个请求有一个唯一的requestid,由几部分组成,还有一些算法保证其唯一性。然后这个requestID贯穿整个请求过程的日志,服务间的相互调用,与数据库中间件的交互都依赖于这个requestID。

以往压测都是写了一个请求ID,并未对这个header做处理,现在得搞起来了。

首先我先新建了一个Java interface,用于使用闭包直接完成这个功能,还有就是其他标记方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.fun.base.interfaces;

import org.apache.http.client.methods.HttpRequestBase;

import java.io.Serializable;

/**
 * 用来标记request,为了记录超时的请求
 */
public interface MarkRequest extends Serializable {

    /**
     * 用来标记base,删除header其中一项,添加一项
     *
     * @param base
     * @return
     */
    public String mark(HttpRequestBase base);


}

然后我再ThreadLimitTimesCountThreadLimitTimeCount实现类中使用这个接口对象,两个实现类的代码已经发过了性能测试框架第二版,这里只写一个:

  • 中间用到了深拷贝的方法,在之前也记录过了拷贝HttpRequestBase对象,目前是每一个线程对应一个mark对象,而不是多线程共享,下面会看到效果。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.fun.frame.thead;

import com.fun.base.constaint.ThreadLimitTimesCount;
import com.fun.base.interfaces.MarkRequest;
import com.fun.config.Constant;
import com.fun.config.HttpClientConstant;
import com.fun.frame.Save;
import com.fun.frame.excute.Concurrent;
import com.fun.frame.httpclient.FanLibrary;
import com.fun.frame.httpclient.FunRequest;
import com.fun.frame.httpclient.GCThread;
import com.fun.utils.Time;
import org.apache.http.client.methods.HttpRequestBase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

/**
 * http请求多线程类
 */
public class RequestThreadTimes extends ThreadLimitTimesCount {

    private static final long serialVersionUID = -2751325651625435070L;

    static Logger logger = LoggerFactory.getLogger(RequestThreadTimes.class);

    /**
     * 记录总的请求超时的情况
     */
    public static Vector<String> requestMark = new Vector<>();

    /**
     * 请求
     */
    public HttpRequestBase request;

    /**
     * 标记对象
     */
    public MarkRequest mark;

    /**
     * 记录当前线程超时请求
     */
    public List<String> marks = new ArrayList<>();

    /**
     * 单请求多线程多次任务构造方法
     *
     * @param request 被执行的请求
     * @param times   每个线程运行的次数
     */
    public RequestThreadTimes(HttpRequestBase request, int times) {
        this.request = request;
        this.times = times;
        this.mark = new MarkRequest() {

            private static final long serialVersionUID = 5599842482575655279L;

            @Override
            public String mark(HttpRequestBase base) {
                return EMPTY;
            }
        };
    }

    /**
     * 应对对每个请求进行标记的情况
     *
     * @param request
     * @param times
     * @param mark
     */
    public RequestThreadTimes(HttpRequestBase request, int times, MarkRequest mark) {
        this(request, times);
        this.mark = mark;
    }

    protected RequestThreadTimes() {
        super();
    }

    @Override
    public void before() {
        super.before();
        GCThread.starts();
    }

    /**
     * @throws Exception
     */
    @Override
    protected void doing() throws Exception {
        FanLibrary.excuteSimlple(request);
    }

    @Override
    protected void after() {
        requestMark.addAll(marks);
        GCThread.stop();
        synchronized (RequestThreadTimes.class) {
            if (countDownLatch.getCount() == 0) Save.saveStringList(requestMark, Constant.DEFAULT_STRING);
        }
    }

    @Override
    public void run() {
        try {
            before();
            List<Long> t = new ArrayList<>();
            long ss = Time.getTimeStamp();
            for (int i = 0; i < times; i++) {
                try {
                    String m = this.mark.mark(request);
                    long s = Time.getTimeStamp();
                    doing();
                    long e = Time.getTimeStamp();
                    long diff = e - s;
                    t.add(diff);
                    if (diff > HttpClientConstant.MAX_ACCEPT_TIME) marks.add(diff + CONNECTOR + m);
                    excuteNum++;
                    if (status()) break;
                } catch (Exception e) {
                    logger.warn("执行任务失败!", e);
                    errorNum++;
                }
            }
            long ee = Time.getTimeStamp();
            logger.info("执行次数:{},错误次数: {},总耗时:{} s", times, errorNum, (ee - ss) / 1000 + 1);
            Concurrent.allTimes.addAll(t);
        } catch (Exception e) {
            logger.warn("执行任务失败!", e);
        } finally {
            if (countDownLatch != null)
                countDownLatch.countDown();
            after();
        }

    }

    @Override
    public RequestThreadTimes clone() {
        RequestThreadTimes threadTimes = new RequestThreadTimes();
        threadTimes.times = this.times;
        threadTimes.request = FunRequest.cloneRequest(request);
        threadTimes.mark = deepClone(mark);
        return threadTimes;
    }

}

我自己写了一个使用Demo:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 def "测试并发情况下记录响应标记符的"() {
        given:
        HttpGet httpGet = FanLibrary.getHttpGet("https://cn.bing.com/");
        MarkRequest mark = new MarkRequest() {

            String m;

            @Override
            public String mark(HttpRequestBase base) {
                base.removeHeaders("requestid");
                m = m == null ? RString.getStringWithoutNum(4) : m
                String value = "fun_" + m + CONNECTOR + Time.getTimeStamp();
                base.addHeader("requestid", value);
                return value;
            }

        };
        FanLibrary.getHttpResponse(httpGet);
        HttpClientConstant.MAX_ACCEPT_TIME = -1
        RequestThreadTimes threadTimes = new RequestThreadTimes(httpGet, 2, mark);
        new Concurrent(threadTimes, 2).start();

        output(RequestThreadTimes.requestMark)

    }

下面是记录的结果如下,可以看到,一共出现了两个m的值,后面跟的是时间戳,这样既保证了requestID唯一性,也可以对线程进行归类。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
80_fun_QkhQ_1578367527661
103_fun_QkhQ_1578367527742
101_fun_zwtk_1578367527661
107_fun_zwtk_1578367527763

  • 郑重声明:文章首发于公众号“FunTester”,禁止第三方(腾讯云除外)转载、发表。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-01-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FunTester 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【C++】继承 ⑦ ( 继承中的对象模型分析 | 继承中的构造函数和析构函数 )
上述 继承 的过程中 , 每一层继承 , 都继承了上一级 父类的 成员变量 , 同时自己也定义了新的成员变量 ;
韩曙亮
2023/10/23
2590
【C++】继承 ⑦ ( 继承中的对象模型分析 | 继承中的构造函数和析构函数 )
【C++】构造函数初始化列表 ④ ( 构造函数 和 析构函数 调用顺序分析 )
析构函数调用顺序 与 构造函数调用顺序相反 , 直接 将 构造函数 调用顺序 倒序排列即可 ;
韩曙亮
2023/10/15
3580
【C++】构造函数初始化列表 ④ ( 构造函数 和 析构函数 调用顺序分析 )
C++新旅程:类的构造函数和析构函数
https://cloud.tencent.com/developer/article/2466159?shareByChannel=link
池央
2024/11/22
570
C++之继承中的构造和析构学习总结
在我们前面学习过类中的构造函数,以及析构函数,那么自然而然,在继承关系中,必然是存在着析构和构造着。
用户6280468
2022/03/21
3660
c++那些事儿3.0 继承
一般形式 class class_name:继承方式 基类名{ code } 继承方式有三种: public ,protected,private. //java好像都是public继承。 单继承 多继承,多继承会很复杂,所以java,c sharp都采用interface。 类函数: 构造函数 先执行父类的构造函数,在执行子类的构造函数。 一般形式 派生类的构造函数(参数列表)
热心的社会主义接班人
2018/04/27
5940
c++那些事儿3.0 继承
c++系列之一构造函数
这里有三个类,其中A,C类是B的父类,然后在Main函数中声明一个B类型的变量,然后程序的输出是这样的:
早起的鸟儿有虫吃
2019/05/05
6890
c++系列之一构造函数
七、构造函数与析构函数
在C++中,构造函数是一种特殊的成员函数,它用于初始化类的对象。当创建类的对象时,构造函数会被自动调用。构造函数的名字与类的名字相同,并且没有返回类型(即使是void也没有)。
用户11332765
2024/10/28
1540
C++: 06---构造函数析构函数
拷贝构造函数: 用一个已经存在的对象来生成一个相同类型的新对象。(浅拷贝) 默认的拷贝构造函数: 如果自定义了拷贝构造函数,编译器就不在生成默认的拷贝构造函数。 如果没有自定义拷贝构造函数,但在代码中用到了拷贝构造函数,编译器会生成默认的拷贝构造函数。 深拷贝&浅拷贝: 系统默认的拷贝构造函数是浅拷贝,类中含有指针类型的变量,须自定义拷贝构造函数用深拷贝来实现。 浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,所指向的空间内容并没有复制,而是由两个对象共用。深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。
用户3479834
2021/02/03
6770
C++: 06---构造函数析构函数
【C++】构造函数初始化列表 ② ( 构造函数 为 初始化列表 传递参数 | 类嵌套情况下 的 构造函数 / 析构函数 执行顺序 )
在下面的代码中 , B 类的 有参构造函数 , 传入了 3 个参数 , 这三个参数都不在函数体中使用 , 而是在 参数列表中使用 ,
韩曙亮
2023/10/15
2900
【C++】构造函数初始化列表 ② ( 构造函数 为 初始化列表 传递参数 | 类嵌套情况下 的 构造函数 / 析构函数 执行顺序 )
探索C/C++的奥秘之C++中的继承
继承的好处是可以复用,通俗点来讲就是父辈打下的江山或者是基业我们可以继续使用。继承是类设计层次的复用。
用户11290648
2025/01/13
1250
探索C/C++的奥秘之C++中的继承
C++学习————第五天(构造函数 析构函数 拷贝构造函数)
关于后面三个默认函数:https://blog.csdn.net/island1314/article/details/137756026?spm=1001.2014.3001.5502
IsLand1314
2024/10/15
1270
C++学习————第五天(构造函数 析构函数 拷贝构造函数)
C++继承
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,继承允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类、子类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用。
用户11316056
2024/10/16
700
C++继承
【深入浅出C#】章节 4: 面向对象编程基础:构造函数和析构函数
构造函数和析构函数是面向对象编程中的两个重要概念,它们在对象的创建和销毁过程中起着关键作用。 构造函数是一个特殊的成员函数,用于在创建对象时初始化对象的数据成员。它的主要作用是为对象分配内存空间并初始化对象的状态。构造函数具有与类同名的特点,并且没有返回类型。通过构造函数,可以确保对象在创建时具有有效的初始状态。构造函数可以被重载,这意味着可以根据需要定义多个具有不同参数的构造函数。 析构函数是一个特殊的成员函数,用于在对象销毁时执行必要的清理操作。它的主要作用是释放对象占用的资源,例如释放动态分配的内存、关闭打开的文件或释放其他外部资源。析构函数的名称与类名相同,前面加上一个波浪线(~)作为前缀。析构函数在对象销毁时自动调用,无法手动调用。 构造函数和析构函数在对象的生命周期中起着关键作用。构造函数确保对象在创建时具有合适的初始化状态,而析构函数则确保对象在销毁时进行必要的清理操作。这种对象创建和销毁的过程对于程序的正确运行和资源管理非常重要。合理使用构造函数和析构函数可以提高代码的可读性、可维护性和可靠性,同时避免内存泄漏和资源泄漏等问题。
喵叔
2023/07/09
7570
构造函数以及析构函数在PHP中需要注意的地方
基本上所有的编程语言在类中都会有构造函数和析构函数的概念。构造函数是在函数实例创建时可以用来做一些初始化的工作,而析构函数则可以在实例销毁前做一些清理工作。相对来说,构造函数我们使用得非常多,而析构函数则一般会用在释放资源上,比如数据库链接、文件读写的句柄等。
硬核项目经理
2020/02/17
1.7K0
当类构造与析构的时候...
2、当类B含有类A的对象,并且使用类B的默认构造函数时,会调用类A的默认构造函数。
看、未来
2021/10/09
6460
当类构造与析构的时候...
【C++】C++构造函数和析构函数
C++提供构造函数来处理对象的初始化。 构造函数是一种特殊的成员函数,不需要用户来调用,定义对象时被自动执行。 构造函数名字与类名相同,无返回类型(void也不能有哦)。
谙忆
2021/01/21
6210
【C++】继承 ⑧ ( 继承 + 组合 模式的类对象 构造函数 和 析构函数 调用规则 )
继承关系 : C 类 继承了 B 类 class C : public B , B 类 继承了 A 类 class B : public A ;
韩曙亮
2023/10/25
2200
【C++】继承 ⑧ ( 继承 + 组合 模式的类对象 构造函数 和 析构函数 调用规则 )
最全面的c++中类的构造函数高级使用方法及禁忌
编译后报错:错误:constructors cannot be declared ‘virtual’,可见构造函数是不能声明为virtual的,这与虚函数的机制有关,虚函数是存放在虚表的,而虚表是在构造函数执行完成以后才建立的,构造函数声明为virtual就会陷入到是先有鸡还是先有蛋的尴尬境地,所以编译器做了限制。
cpp加油站
2021/05/17
1.8K0
C++类的构造函数与析构函数
C++中每个类都有其构造与析构函数,它们负责对象的创建和对象的清理和回收,即使我们不写这两个,编译器也会默认为我们提供这些构造函数。下面仍然是通过反汇编的方式来说明C++中构造和析构函数是如何工作的。
Masimaro
2018/08/31
1.6K0
C++:构造函数与析构函数
构造函数用于对象的初始化,一旦建立对象,就需要有一个有意义的初始值,构造函数的作用即是在对象初始化时被调用,给对象分配内存空间以及完成初始化。
字节星球Henry
2021/08/09
5640
推荐阅读
相关推荐
【C++】继承 ⑦ ( 继承中的对象模型分析 | 继承中的构造函数和析构函数 )
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验