当前位置: 首页 > article >正文

【2】高并发导出场景下,服务器性能瓶颈优化方案-异步导出

Java 异步导出是一种在处理大量数据或复杂任务时优化性能和用户体验的重要技术。

1. 异步导出的优势

     异步导出是指将导出操作从主线程中分离出来,通过后台线程或异步任务完成数据处理和文件生成。这种方式可以显著减少用户等待时间,避免系统阻塞,并提升整体性能。

优势:
  • 提高响应速度:用户在触发导出操作后立即返回,无需等待导出完成,从而提升用户体验。
  • 降低系统负载:将耗时操作移至后台执行,减少主线程的占用,提高系统并发能力。
  • 适用于大数据量场景:在处理百万级甚至更大的数据量时,异步导出能够有效避免内存溢出和性能瓶颈。

2. 实现方式

Java 异步导出可以通过多种方式实现,包括多线程、异步框架、注解以及特定库的支持。

(1)多线程实现

使用 Java 的 Thread 类或 ExecutorService 来创建独立线程处理导出任务。例如:

ExecutorService executor = Executors.newFixedThreadPool(10);
executor.submit(() -> {
    // 执行导出逻辑
});

这种方式简单直接,适合处理较小的数据量。

(2)异步框架支持

使用 Spring 框架中的异步方法(@Async 注解)来实现异步导出:

@Service
public class ExportService {
    @Async("asyncExecutor")
    public void exportData() {
        // 导出逻辑
    }
}

这种方式可以方便地管理异步任务,并支持任务调度和状态跟踪。

(3)注解优化

通过自定义注解(如 @Export)标记需要异步处理的方法,简化代码逻辑。

(4)特定库支持

使用 EasyExcel 等库提供的异步导出功能:

public void exportDataAsync() {
    EasyExcel.write(new File("output.xlsx"), YourDataClass.class)
        .sheet("Sheet1")
        .doWrite(dataList);
}
(5)下载任务管理+定时任务+文件存储服务

   用户点击导出时,先记录用户请求。通过定时任务再执行导出,并将导出的文件上传到文件存储服务(例如腾讯的COS)。

//1.下载调用的方法 
public void asyncExportData(QueryParam param) {
        //exportData为定时任务需要触发的实际导出方法
        ExportTask task = ExportTask.builder()
                .methodClassName(XXService.class.getName())
                .methodName("exportData")
                .queryParam(JSON.toJSONString(param))
                .paramClassName(param.getClass().getName())
                .build();
        this.save(task);
 }
//2.定时任务遍历导出任务表,查询待执行导出的记录 
public void executeExportTask() {
        List<ExportTask> list = exportTaskService.listExportTask(pageSize);
        log.info("当前处理任务exportTask={}", JSON.toJSON(list));
        if (CollUtil.isEmpty(list)) {
            return;
        }
        for (ExportTask task : list) {
            try {
                Class<?> methodClass = ClassUtil.loadClass(task.getMethodClassName(), false);
                Object methodBean = SpringUtil.getBean(methodClass);
                Class<Object> paramClass = ClassUtil.loadClass(task.getParamClassName(), false);
                ObjectMapper mapper = new ObjectMapper();
                Object value = mapper.readValue(task.getQueryParam(), paramClass);
                methodClass.getMethod(task.getMethodName(), paramClass).invoke(methodBean, value);
            } catch (Exception e) {
                log.error("taskId={}执行异常,异常原因:{}", task.getId(),  e);
            }
        }
    }
//3.实际的导出方法
public void exportData(QueryParam param) {
        //使用param参数,从数据库查询业务数据
        List<ExportDto> list= new ArrayList<>();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        EasyExcel.write(out, ExportDto.class)
                .sheet(0)
                .doWrite(list);
}
public class ExportTask {

    protected Long id;

    private String fileUrl;

    private Integer processStatus;

    private String failCause;

    //导出方法对应的类全限定名
    private String methodClassName;

    //导出方法名
    private String methodName;

    //请求参数
    private String queryParam;

    //请求参数对应的类名
    private String paramClassName;

    private Date createDateTime;

    private Date lastUpdateDateTime;
}

3. 具体案例分析

(1)大数据量导出

对于超过 5 万条数据的导出任务,建议将数据插入数据库队列并等待处理。小于 5 万条的数据则直接调用处理方法。

(2)Excel 导出优化

使用 EasyExcel 的异步导出功能,可以显著提高导出效率。

(3)文件上传与下载

结合异步导出与文件存储服务(如阿里云OSS),可以实现文件的高效上传和下载。

4. 注意事项

  • 任务状态跟踪:确保能够实时监控任务进度,并提供用户友好的反馈界面。
  • 错误处理:在异步任务中加入异常捕获和日志记录,以便于问题排查。
  • 资源管理:合理分配线程池资源,避免资源耗尽导致系统崩溃。

http://www.kler.cn/a/535910.html

相关文章:

  • 1-R语言概述
  • DKG(Distributed Key Generation)协议
  • Spring的Bean的生命周期 笔记250206
  • 概念AIGC
  • JDK9新特性
  • docker pull Error response from daemon问题
  • AI大模型评测对比2—ChatGPT对比DeepSeek
  • DeepSeek-VL2论文解读:用于高级多模态理解的专家混合视觉语言模型
  • 图论 - 临接矩阵与临接表介绍与分析对比
  • Linux进阶——远程连接服务器
  • salesforce SF CLI 数据运维经验分享
  • 2025模仿游戏 别人怎么做就什么做 做的过程中再加入自己的元素 模仿与创新
  • 深度学习中模型训练的过拟合与欠拟合问题
  • 计算机毕业设计Python+大模型疲劳驾驶检测系统 自动驾驶 面部多信息特征融合的疲劳驾驶检测系统 驾驶员疲劳驾驶风险检测 深度学习 机器学习 大数据
  • innoDB 如何解决幻读
  • 动手学图神经网络(10):利用 PyTorch Geometric 进行图分类
  • 设计模式-状态模式:让对象的行为随状态改变而清晰可控
  • 设计模式1:工厂模式
  • 软件模拟I2C案例(寄存器实现)
  • 基于微信小程序的在线点餐(堂食)平台的设计与实现ssm+论文源码调试讲解
  • .net8.0使用EF连接sqlite数据库及使用Gridify实现查询的简易实现
  • Python“鉴黄”小程序,自动识别检测物体的颜色
  • 【数据结构】(5) ArrayList 顺序表
  • 确保数据一致性:RabbitMQ 消息传递中的丢失与重复问题详解
  • 如何查看:Buildroot所使用Linux的版本号、gcc交叉编译工具所使用的Linux的版本号、开发板上运行的Linux系统的版本号
  • 使用外骨骼灵活远程控制协作机器人案例