【工作实践(多线程)】十个线程任务生成720w测试数据对系统进行性能测试

本文涉及的产品
性能测试 PTS,5000VUM额度
简介: 【工作实践(多线程)】十个线程任务生成720w测试数据对系统进行性能测试

起因

  1. 公司最近有个客户需要把2-3w台设备各类数据存放到我们平台,这么多设备带来的数据量一年下来单表大概会达到720w,这样会使得平台某些分页查询或相关业务效率变慢。所以想让客户自己去阿里云买服务器,但是客户不想管理,想丢在我们平台。那也没办法,客户是上帝,能做是能做,不过得加钱!!! 哈哈哈
  2. 要帮客户存储数据,那得知道买多大的服务器合适,或者租多大服务器,一年得多少钱,这个得有一定的评估。所以就得生成一年的数据量了,进行存储和效率测试,系统后台的性能调优。

思路

  1. 要生成720w数据得有基础的2w台设备基础信息,所以现同普通方式生成了2w基础数据
  2. 720w = 2w * 360 每个表一天一笔数据,一年按照360算,一共720w
  3. 数据量有这么大,于是我 Ctrl+Alt+Del 打开任务管理器,看了看电脑的配置,评估一下CPU能扛得住怎样的摩擦,发现6核12处理器
  4. 那就给他来十个线程,每个线程处理2000基础数据生成72w,应该可以生成出来。

实践

1.新建定时器

@Slf4j
@Configuration
@EnableScheduling
public class InsertBatchMeterArchiveTask implements SchedulingConfigurer {
    @Autowired
    private MeterArchiveService meterArchiveService;
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addTriggerTask(() -> {
            try {
                meterArchiveService.insertBatchBaseInfo();
            } catch (Exception e) {
                log.error("insertBatchBaseInfo meter error:{}", e.getMessage());
            }
        }, triggerContext -> {
            String cron = "0 37 12 * * ? "; 
            return new CronTrigger(cron).nextExecutionTime(triggerContext);
        });
    }
}
   
  1. 业务实现
public static List<Date> dateList = new ArrayList<>(360);
@Override
    public void insertBatchBaseInfo() throws InterruptedException {
        for (int i = 0; i < 360; i++) {
            Calendar instance = Calendar.getInstance();
            instance.setTime(CommonUtil.getCurrentDate());
            instance.add(Calendar.DAY_OF_YEAR, -i);
            dateList.add(instance.getTime());
        }
        // id 20062 --> 40061
        System.out.println(System.currentTimeMillis());
        List<MeterArchiveDO> meterArchiveDOS = meterArchiveMapper.selectList(new QueryWrapper<MeterArchiveDO>()
                .eq("area_id", 9).gt("id", 100));
        int listSize = meterArchiveDOS.size();
        int toIndex = 2000;
        //用map存起来新的分组后数据
        Map<String, List<MeterArchiveDO>> map = new HashMap();
        int keyToken = 0;
        for (int i = 0; i < meterArchiveDOS.size(); i += 2000) {
            //作用为toIndex最后没有2000条数据则剩余几条newList中就装几条
            toIndex = (i + 2000 > listSize ? listSize - i : toIndex);
            List newList = meterArchiveDOS.subList(i, i + toIndex);
            map.put("keyName" + keyToken, newList);
            keyToken++;
        }
        System.out.println(System.currentTimeMillis());
        // 处理生成数据
        dealGenerateData(map);
    }
  • 这里之前发生了线程不安全问题
    原因是在线程实现里面用到了Calendar进行时间处理,导致时间错乱,因为Calendar是单例的,每个线程任务都使用了这个变化的时间。所以通过声明全局变量,把360天都生成出来,传到线程处理业务中,就不会有这种情况了。
  1. 处理生成数据
/**
     * 处理生成数据
     *
     * @param map
     */
    private void dealGenerateData(Map map) throws InterruptedException {
        //线程池10个线程
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        //第一批十个任务
        List<StartAgent> agentsStart = new ArrayList();
        for (int i = 0; i < 10; i++) {
            agentsStart.add(new StartAgent((List<MeterArchiveDO>) map.get("keyName" + i), meterDayFlowWaterMapper,dateList));
        }
        List<List<StartAgent>> task = new ArrayList<>();
        task.add(agentsStart);
        //记录任务执行时间
        long t1 = System.currentTimeMillis();
        CountDownLatch c;
        //循环任务组
        for (List<StartAgent> startList : task) {
            //定义线程阻塞为10
            c = new CountDownLatch(11);
            for (StartAgent agent : startList) {
                agent.setCountDownLatch(c);
                executorService.submit(agent);
            }
            c.await();
        }
        executorService.shutdown();
    }
  1. 具体线程内业务实现
@Data
public class StartAgent implements Runnable {
    private CountDownLatch countDownLatch;
    private List<MeterArchiveDO> meterArchiveDOS;
    private MeterDayFlowWaterMapper meterDayFlowWaterMapper;
    private List<Date> dateList;
    public StartAgent(List<MeterArchiveDO> meterArchiveDOS, MeterDayFlowWaterMapper meterDayFlowWaterMapper, List<Date> dateList) {
        this.meterArchiveDOS = meterArchiveDOS;
        this.meterDayFlowWaterMapper = meterDayFlowWaterMapper;
        this.dateList = dateList;
    }
    @Override
    public void run() {
        try {
            System.out.println("开始启动节点:" + Thread.currentThread().getName());
            MeterDayFlowWaterDO meterDayFlowWaterDO = new MeterDayFlowWaterDO();
            for (MeterArchiveDO meterArchiveDO : meterArchiveDOS) {
                for (int i = 0; i < 360; i++) {
                    BeanUtils.copyProperties(meterArchiveDO, meterDayFlowWaterDO);
                    meterDayFlowWaterDO.setMeterReadTime(dateList.get(i));
                    meterDayFlowWaterDO.setMeterSaveTime(dateList.get(i));
                    meterDayFlowWaterDO.setMeterPositiveFlow("6.66");
                    meterDayFlowWaterDO.setMeterReverseFlow("0.05");
                    meterDayFlowWaterDO.setMeterIncrementFlow("1.38");
                    meterDayFlowWaterDO.setSync(1);
                    meterDayFlowWaterDO.setRemainingAmount("100");
                    meterDayFlowWaterMapper.insert(meterDayFlowWaterDO);
                }
            }
            System.out.println(Thread.currentThread().getName() + "执行完毕");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //注意一定要在finally调用countDown,否则产生异常导致没调用到countDown造成程序死锁
            countDownLatch.countDown();
        }
    }
    public void setCountDownLatch(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }
}

测试

欢迎大佬指点探讨!!!

相关实践学习
通过性能测试PTS对云服务器ECS进行规格选择与性能压测
本文为您介绍如何利用性能测试PTS对云服务器ECS进行规格选择与性能压测。
目录
打赏
0
0
0
0
55
分享
相关文章
浅谈网页端IM技术及相关测试方法实践(包括WebSocket性能测试)
最开始转转的客服系统体系如IM、工单以及机器人等都是使用第三方的产品。但第三方产品对于转转的业务,以及客服的效率等都产生了诸多限制,所以我们决定自研替换第三方系统。下面主要分享一下网页端IM技术及相关测试方法,我们先从了解IM系统和WebSocket开始。
74 4
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
51 5
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
C#集合数据去重的5种方式及其性能对比测试分析
C#集合数据去重的5种方式及其性能对比测试分析
41 11
C#集合数据去重的5种方式及其性能对比测试分析
C#集合数据去重的5种方式及其性能对比测试分析
59 10
探索软件测试的深度与广度:从理论到实践
在数字化时代,软件已成为我们生活中不可或缺的一部分。随着技术的不断进步和用户需求的多样化,确保软件质量变得尤为重要。本文将深入浅出地介绍软件测试的核心概念、类型及其在软件开发生命周期中的重要性。我们将通过实际案例,展示如何实施有效的测试策略,并探讨自动化测试的未来趋势,旨在为读者提供一套完整的软件测试知识体系,帮助提升软件质量和开发效率。
探索软件测试的奥秘:从理论到实践
在软件开发的宇宙中,软件测试犹如一颗璀璨的星辰,指引着质量的方向。本文将带你穿梭于软件测试的理论与实践之间,揭示其内在的逻辑和魅力。从测试的重要性出发,我们将探讨不同类型的测试方法,并通过实际案例分析,深入理解测试用例的设计和应用。最后,我们将通过一个代码示例,展示如何将理论知识转化为实际操作,确保软件质量的同时,也提升你的测试技能。让我们一起踏上这段探索之旅,发现软件测试的无限可能。
电商API的测试与用途:深度解析与实践
在电子商务蓬勃发展的今天,电商API成为连接电商平台、商家、消费者和第三方开发者的重要桥梁。本文深入探讨了电商API的核心功能,包括订单管理、商品管理、用户管理、支付管理和物流管理,并介绍了有效的测试技巧,如理解API文档、设计测试用例、搭建测试环境、自动化测试、压力测试、安全性测试等。文章还详细阐述了电商API的多样化用途,如商品信息获取、订单管理自动化、用户数据管理、库存同步、物流跟踪、支付处理、促销活动管理、评价管理、数据报告和分析、扩展平台功能及跨境电商等,旨在为开发者和电商平台提供有益的参考。
121 0
接口测试新选择:Postman替代方案全解析
在软件开发中,接口测试工具至关重要。Postman长期占据主导地位,但随着国产工具的崛起,越来越多开发者转向更适合中国市场的替代方案——Apifox。它不仅支持中英文切换、完全免费不限人数,还具备强大的可视化操作、自动生成文档和API调试功能,极大简化了开发流程。
大前端之前端开发接口测试工具postman的使用方法-简单get接口请求测试的使用方法-简单教学一看就会-以实际例子来说明-优雅草卓伊凡
大前端之前端开发接口测试工具postman的使用方法-简单get接口请求测试的使用方法-简单教学一看就会-以实际例子来说明-优雅草卓伊凡
91 10
大前端之前端开发接口测试工具postman的使用方法-简单get接口请求测试的使用方法-简单教学一看就会-以实际例子来说明-优雅草卓伊凡