zoukankan      html  css  js  c++  java
  • 性能测试中标记每个请求

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

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

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

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

    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对象,而不是多线程共享,下面会看到效果。
    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:

     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唯一性,也可以对线程进行归类。

    80_fun_QkhQ_1578367527661
    103_fun_QkhQ_1578367527742
    101_fun_zwtk_1578367527661
    107_fun_zwtk_1578367527763
    

    • 郑重声明:文章首发于公众号“FunTester”,禁止第三方(腾讯云除外)转载、发表。

    技术类文章精选

    非技术文章精选

  • 相关阅读:
    JS_Boolean Logic
    js String
    .Net之路(二)简介
    自考 操作系统概论计算机系统
    IT大学生最重要的五个能力
    数据库表及字段命名规范
    简述MVC分层
    .Net之路(一)概述
    设计模式(4)迭代器模式
    .Net之路(三)如何连接数据库?
  • 原文地址:https://www.cnblogs.com/FunTester/p/12179129.html
Copyright © 2011-2022 走看看