前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >固定QPS压测初试

固定QPS压测初试

作者头像
FunTester
发布2020-11-09 09:50:45
1.6K0
发布2020-11-09 09:50:45
举报
文章被收录于专栏:FunTesterFunTester

之前写过一篇固定QPS压测模式探索文章,个人认为这个模型相比「固定线程数」并发请求压测服务的模型更加贴近实际情况,比较适合做负载测试。在最近的工作中尝试使用「固定QPS」的压测方案,有了一些实践成果(大部分还是修复了BUG),分享一下。

先说一下实践代码,然后分享一下自己修复的两个BUG。

固定QPS实践

先讲一下最常用的HTTP请求的负载测试实践,跳过单个请求的实践,这里用两个request,通过一个list完成存储,然后创建测试任务。

代码语言:javascript
复制
        def requests = []
        def base = getBase()
        def order = new Order(base)
        order.create(21, 17, "FunTester", "", 1, 1)
        requests << FanLibrary.lastRequest
        order.edit()
        requests << FanLibrary.lastRequest

        def threads = []

        requests.size().times {
            threads << new RequestTimesFixedQps<>(5, 50, new HeaderMark("requestid"), requests[it])
        }

        new FixedQpsConcurrent(threads,"固定QPS实践").start()

        allOver()

下面分享一下通用型的内部类实现的测试脚本,只需要实现一下doing()方法和clone()方法即可。

代码语言:javascript
复制
    public static void main(String[] args) {
        TT qps = new TT(5, 50);
        new FixedQpsConcurrent(qps).start();

    }

    static class TT extends FixedQpsThread{


        public TT(int i, int i1) {
            super(null, i1, i, null, true);
        }

        @Override
        protected void doing() throws Exception {
            sleep(1);
        }

        @Override
        public TT clone() {
            return this;
        }


    }

异步补偿线程的线程池状态验证

旧代码:

代码语言:javascript
复制
@Override
        public void run() {
            logger.info("补偿线程开始!");
            while (key) {
                sleep(HttpClientConstant.LOOP_INTERVAL);
                int actual = executeTimes.get();
                int qps = baseThread.qps;
                long expect = (Time.getTimeStamp() - FixedQpsConcurrent.this.startTime) / 1000 * qps;
                if (expect > actual + qps) {
                    logger.info("期望执行数:{},实际执行数:{},设置QPS:{}", expect, actual, qps);
                    range((int) expect - actual).forEach(x -> {
                        sleep(100);
                        executorService.execute(threads.get(this.i++ % queueLength).clone());
                    });
                }
            }
            logger.info("补偿线程结束!");
        }

这里有个问题,在执行补偿的操作时候,线程池可能已经关闭了,可能会导致报错。

Exception in thread "Thread-1" java.util.concurrent.RejectedExecutionException: Task com.fun.frame.execute.FixedQpsConcurrent$TT@5e6bf970 rejected from java.util.concurrent.ThreadPoolExecutor@15897721[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 50]

这里修改代码如下:

代码语言:javascript
复制
        @Override
        public void run() {
            logger.info("补偿线程开始!");
            try {
                while (key) {
                    sleep(HttpClientConstant.LOOP_INTERVAL);
                    int actual = executeTimes.get();
                    int qps = baseThread.qps;
                    long expect = (Time.getTimeStamp() - FixedQpsConcurrent.this.startTime) / 1000 * qps;
                    if (expect > actual + qps) {
                        logger.info("期望执行数:{},实际执行数:{},设置QPS:{}", expect, actual, qps);
                        range((int) expect - actual).forEach(x -> {
                            sleep(100);
                            if (!executorService.isShutdown())
                                executorService.execute(threads.get(this.i++ % queueLength).clone());
                        });
                    }
                }
                logger.info("补偿线程结束!");
            } catch (Exception e) {
                logger.error("补偿线程发生错误!", e);
            }
        }

增加了executorService.isShutdown()的验证。

修改计数BUG

旧代码:

代码语言:javascript
复制
 @Override
    public void run() {
        try {
            before();
            threadmark = this.mark == null ? EMPTY : this.mark.mark(this);
            long s = Time.getTimeStamp();
            doing();
            long e = Time.getTimeStamp();
            long diff = e - s;
            FixedQpsConcurrent.executeTimes.getAndIncrement();
            FixedQpsConcurrent.allTimes.add(diff);
            if (diff > HttpClientConstant.MAX_ACCEPT_TIME)
                FixedQpsConcurrent.marks.add(diff + CONNECTOR + threadmark);
        } catch (Exception e) {
            FixedQpsConcurrent.errorTimes.getAndIncrement();
            logger.warn("执行任务失败!,标记:{}", threadmark, e);
        } finally {
            after();
        }
    }

由于是在doing()方法之后做的计数增加,可能会导致异步补偿线程判断是否需要补偿,补偿额度出现过度补偿的问题。虽然在较长时间的测试中会慢慢中和掉这个影响,但我还是决定修改掉。

这里修改代码如下:

代码语言:javascript
复制
    @Override
    public void run() {
        try {
            before();
            threadmark = this.mark == null ? EMPTY : this.mark.mark(this);
            FixedQpsConcurrent.executeTimes.getAndIncrement();
            long s = Time.getTimeStamp();
            doing();
            long e = Time.getTimeStamp();
            long diff = e - s;
            FixedQpsConcurrent.allTimes.add(diff);
            if (diff > HttpClientConstant.MAX_ACCEPT_TIME)
                FixedQpsConcurrent.marks.add(diff + CONNECTOR + threadmark);
        } catch (Exception e) {
            FixedQpsConcurrent.errorTimes.getAndIncrement();
            logger.warn("执行任务失败!,标记:{}", threadmark, e);
        } finally {
            after();
        }
    }
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-11-05,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 固定QPS实践
  • 异步补偿线程的线程池状态验证
  • 修改计数BUG
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档