【工作实践(多线程)】十个线程任务生成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进行规格选择与性能压测。
相关文章
|
1天前
|
数据采集 DataWorks 安全
DataWorks产品使用合集之选择独享调度,数据集成里可以使用,但是数据地图里面测试无法通过,是什么原因导致的
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
7 0
DataWorks产品使用合集之选择独享调度,数据集成里可以使用,但是数据地图里面测试无法通过,是什么原因导致的
|
1天前
|
并行计算 安全 Java
多线程编程中的线程安全问题与解决方案*
多线程编程中的线程安全问题与解决方案*
|
2天前
|
SQL 数据采集 DataWorks
DataWorks操作报错合集之数据集成里面的数据调度独享资源组测试通过了,但是数据地图里无法通过,该如何解决
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
|
3天前
|
XML 测试技术 Linux
技术笔记:sipp重放rtp数据测试FreeSWITCH
技术笔记:sipp重放rtp数据测试FreeSWITCH
|
4天前
|
SQL 安全 Java
JUC多线程-线程池-Thredalocal-CAS-AQS-死锁
JUC多线程-线程池-Thredalocal-CAS-AQS-死锁
|
4天前
|
数据采集 Java Unix
10-多线程、多进程和线程池编程(2)
10-多线程、多进程和线程池编程
|
4天前
|
安全 Java 调度
10-多线程、多进程和线程池编程(1)
10-多线程、多进程和线程池编程
|
9天前
|
存储 Linux C语言
c++进阶篇——初窥多线程(二) 基于C语言实现的多线程编写
本文介绍了C++中使用C语言的pthread库实现多线程编程。`pthread_create`用于创建新线程,`pthread_self`返回当前线程ID。示例展示了如何创建线程并打印线程ID,强调了线程同步的重要性,如使用`sleep`防止主线程提前结束导致子线程未执行完。`pthread_exit`用于线程退出,`pthread_join`用来等待并回收子线程,`pthread_detach`则分离线程。文中还提到了线程取消功能,通过`pthread_cancel`实现。这些基本操作是理解和使用C/C++多线程的关键。
|
11天前
|
安全 Java
【极客档案】Java 线程:解锁生命周期的秘密,成为多线程世界的主宰者!
【6月更文挑战第19天】Java多线程编程中,掌握线程生命周期是关键。创建线程可通过继承`Thread`或实现`Runnable`,调用`start()`使线程进入就绪状态。利用`synchronized`保证线程安全,处理阻塞状态,注意资源管理,如使用线程池优化。通过实践与总结,成为多线程编程的专家。
|
11天前
|
Java 开发者
告别单线程时代!Java 多线程入门:选继承 Thread 还是 Runnable?
【6月更文挑战第19天】在Java中,面对多任务需求时,开发者可以选择继承`Thread`或实现`Runnable`接口来创建线程。`Thread`继承直接但限制了单继承,而`Runnable`接口提供多实现的灵活性和资源共享。多线程能提升CPU利用率,适用于并发处理和提高响应速度,如在网络服务器中并发处理请求,增强程序性能。不论是选择哪种方式,都是迈向高效编程的重要一步。