【工作实践(多线程)】十个线程任务生成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月前
|
监控 测试技术
如何进行系统压力测试?
【10月更文挑战第11天】如何进行系统压力测试?
100 34
|
9天前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####
|
6天前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
10天前
|
缓存 监控 测试技术
全网最全压测指南!教你如何测试和优化系统极限性能
大家好,我是小米。本文将介绍如何在实际项目中进行性能压测和优化,包括单台服务器和集群压测、使用JMeter、监控CPU和内存使用率、优化Tomcat和数据库配置等方面的内容,帮助你在高并发场景下提升系统性能。希望这些实战经验能助你一臂之力!
24 3
|
9天前
|
Java UED
Java中的多线程编程基础与实践
【10月更文挑战第35天】在Java的世界中,多线程是提升应用性能和响应性的利器。本文将深入浅出地介绍如何在Java中创建和管理线程,以及如何利用同步机制确保数据一致性。我们将从简单的“Hello, World!”线程示例出发,逐步探索线程池的高效使用,并讨论常见的多线程问题。无论你是Java新手还是希望深化理解,这篇文章都将为你打开多线程的大门。
|
19天前
|
缓存 Java 调度
Java中的多线程编程:从基础到实践
【10月更文挑战第24天】 本文旨在为读者提供一个关于Java多线程编程的全面指南。我们将从多线程的基本概念开始,逐步深入到Java中实现多线程的方法,包括继承Thread类、实现Runnable接口以及使用Executor框架。此外,我们还将探讨多线程编程中的常见问题和最佳实践,帮助读者在实际项目中更好地应用多线程技术。
22 3
|
21天前
|
监控 安全 Java
Java多线程编程的艺术与实践
【10月更文挑战第22天】 在现代软件开发中,多线程编程是一项不可或缺的技能。本文将深入探讨Java多线程编程的核心概念、常见问题以及最佳实践,帮助开发者掌握这一强大的工具。我们将从基础概念入手,逐步深入到高级主题,包括线程的创建与管理、同步机制、线程池的使用等。通过实际案例分析,本文旨在提供一种系统化的学习方法,使读者能够在实际项目中灵活运用多线程技术。
|
19天前
|
编解码 安全 Linux
网络空间安全之一个WH的超前沿全栈技术深入学习之路(10-2):保姆级别教会你如何搭建白帽黑客渗透测试系统环境Kali——Liinux-Debian:就怕你学成黑客啦!)作者——LJS
保姆级别教会你如何搭建白帽黑客渗透测试系统环境Kali以及常见的报错及对应解决方案、常用Kali功能简便化以及详解如何具体实现
|
19天前
|
缓存 安全 Java
Java中的多线程编程:从基础到实践
【10月更文挑战第24天】 本文将深入探讨Java中的多线程编程,包括其基本原理、实现方式以及常见问题。我们将从简单的线程创建开始,逐步深入了解线程的生命周期、同步机制、并发工具类等高级主题。通过实际案例和代码示例,帮助读者掌握多线程编程的核心概念和技术,提高程序的性能和可靠性。
13 2
|
20天前
|
Java
Java中的多线程编程:从基础到实践
本文深入探讨Java多线程编程,首先介绍多线程的基本概念和重要性,接着详细讲解如何在Java中创建和管理线程,最后通过实例演示多线程的实际应用。文章旨在帮助读者理解多线程的核心原理,掌握基本的多线程操作,并能够在实际项目中灵活运用多线程技术。