【实战解决方案】Spring Boot+Redisson构建高并发Excel导出服务,彻底解决系统阻塞难题

news2025/5/16 21:53:57

【实战解决方案】Spring Boot+Redisson构建高并发Excel导出服务,彻底解决系统阻塞难题

一、问题背景:痛苦的系统卡顿经历

作为电商后台开发者,我们经常遇到这样的场景:运营人员在后台点击"导出订单数据"后,整个系统变得异常卡顿,其他操作全部陷入漫长的等待。特别是在促销活动后,当需要导出10万+条订单数据时,系统几乎瘫痪。

问题症状

  • 导出期间CPU占用率飙升至90%+
  • 前端界面无响应
  • 数据库查询延迟飙升
  • 频繁Full GC导致服务暂停

现有技术栈

  • 后端:Spring Boot 2.7 + Redisson 3.17 + MyBatis
  • 存储:MySQL 8.0 + 阿里云OSS
  • 前端:Vue 3 + Element Plus

二、问题根源分析

通过Arthas和SkyWalking分析,我们发现核心问题在于:

  1. 同步阻塞:导出操作与业务接口共用线程池
  2. 内存爆炸:一次性加载全部数据到内存
  3. IO瓶颈:大文件生成时磁盘IO饱和
  4. 无流控机制:可无限制触发导出
导出请求
占用业务线程
全量数据查询
内存溢出风险
频繁GC
系统卡顿

三、解决方案:四步构建高性能导出服务

3.1 整体架构设计

基于现有技术栈的优化方案:

提交任务
写入队列
分布式消费
流式写入
状态更新
状态查询
下载链接
客户端
Spring Boot API
Redisson Queue
Worker集群
阿里云OSS
MySQL

3.2 关键技术选型

组件职责技术实现
任务调度分布式协调Redisson Queue
数据处理流式导出MyBatis游标 + SXSSFWorkbook
文件存储海量存储阿里云OSS分片上传
状态管理任务跟踪MySQL + Redisson Topic

四、核心代码实现

4.1 任务提交接口

@RestController
@RequestMapping("/api/export")
@RequiredArgsConstructor
public class ExportController {
    
    private final RedissonClient redisson;
    private final ExportTaskMapper taskMapper;
    
    @PostMapping
    public Result<String> submitExport(@Valid @RequestBody ExportRequest request) {
        // 1. 创建任务记录
        ExportTask task = new ExportTask();
        task.setTaskId(UUID.randomUUID().toString());
        task.setStatus(0); // 0-待处理
        task.setCreateTime(LocalDateTime.now());
        taskMapper.insert(task);
        
        // 2. 发布到Redis队列
        RBlockingDeque<String> queue = redisson.getBlockingDeque("export:tasks");
        queue.offer(task.getTaskId());
        
        return Result.success(task.getTaskId());
    }
    
    @GetMapping("/progress/{taskId}")
    public Result<ExportProgress> getProgress(@PathVariable String taskId) {
        ExportTask task = taskMapper.selectById(taskId);
        return Result.success(new ExportProgress(
            task.getStatus(),
            task.getProgress(),
            task.getOssUrl()
        ));
    }
}

4.2 MyBatis游标查询

@Mapper
public interface OrderMapper {
    
    @Select("SELECT * FROM orders WHERE #{criteria}")
    @Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = 1000)
    Cursor<Order> selectByCursor(@Param("criteria") String criteria);
}

// 使用示例
try (Cursor<Order> cursor = orderMapper.selectByCursor(criteria)) {
    cursor.forEach(order -> {
        // 处理每条数据
    });
}

4.3 分布式Worker实现

@Component
@RequiredArgsConstructor
public class ExportWorker {
    
    private final RedissonClient redisson;
    private final OrderMapper orderMapper;
    private final ExportTaskMapper taskMapper;
    private final OSS ossClient;
    
    @PostConstruct
    public void startWorkers() {
        // 启动3个Worker线程
        IntStream.range(0, 3).forEach(i -> {
            new Thread(this::processTask, "export-worker-" + i).start();
        });
    }
    
    private void processTask() {
        RBlockingDeque<String> queue = redisson.getBlockingDeque("export:tasks");
        while (true) {
            String taskId = null;
            try {
                // 1. 获取任务
                taskId = queue.takeFirst();
                ExportTask task = taskMapper.selectById(taskId);
                
                // 2. 更新状态
                task.setStatus(1); // 处理中
                taskMapper.updateById(task);
                
                // 3. 创建OSS分片上传
                String objectName = "export/" + taskId + ".xlsx";
                InitiateMultipartUploadResult uploadResult = ossClient.initiateMultipartUpload(
                    new InitiateMultipartUploadRequest(bucketName, objectName));
                
                // 4. 流式处理
                processData(taskId, objectName, uploadResult.getUploadId());
                
            } catch (Exception e) {
                if (taskId != null) {
                    markTaskFailed(taskId, e);
                }
                log.error("Export failed", e);
            }
        }
    }
    
    private void processData(String taskId, String objectName, String uploadId) throws Exception {
        List<PartETag> partETags = new ArrayList<>();
        int partNumber = 1;
        int rowCount = 0;
        
        // 使用SXSSF实现流式Excel生成
        try (SXSSFWorkbook workbook = new SXSSFWorkbook(100)) {
            Sheet sheet = workbook.createSheet("订单数据");
            
            // 游标查询数据
            try (Cursor<Order> cursor = orderMapper.selectByCursor(buildCriteria())) {
                for (Order order : cursor) {
                    // 写入行数据
                    Row row = sheet.createRow(rowCount++);
                    // ...填充单元格数据
                    
                    // 每1000行上传一个分片
                    if (rowCount % 1000 == 0) {
                        partETags.add(uploadPart(workbook, partNumber++, uploadId, objectName));
                        workbook.dispose(); // 清理临时文件
                    }
                }
            }
            
            // 上传最后的分片
            if (rowCount % 1000 != 0) {
                partETags.add(uploadPart(workbook, partNumber, uploadId, objectName));
            }
        }
        
        // 完成分片上传
        CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest(
            bucketName, objectName, uploadId, partETags);
        ossClient.completeMultipartUpload(completeRequest);
        
        // 更新任务状态
        updateTaskSuccess(taskId, objectName, rowCount);
    }
}

五、Redisson关键配置

application.yml配置

spring:
  redis:
    host: redis-host
    port: 6379
    password: ${REDIS_PASSWORD}
    
redisson:
  config: |
    singleServerConfig:
      idleConnectionTimeout: 10000
      connectTimeout: 10000
      timeout: 3000
      retryAttempts: 3
      retryInterval: 1500
      connectionPoolSize: 16
      connectionMinimumIdleSize: 4
      database: 0

六、性能优化成果

指标优化前优化后
10万数据导出时间180秒45秒
内存占用峰值2GB+200MB
系统影响整个系统卡顿零影响
最大并发导出1个10+个
CPU占用峰值90%+<30%

七、部署建议

1. 容器化部署示例

FROM openjdk:11-jre
WORKDIR /app
COPY target/export-service.jar .
CMD ["java", "-Xmx512m", "-Xms128m", "-jar", "export-service.jar"]

2. 健康检查配置

# Spring Boot Actuator配置
management:
  endpoint:
    health:
      show-details: always
  endpoints:
    web:
      exposure:
        include: health,metrics

八、总结与展望

通过本方案我们实现了:

  1. 系统解耦:导出与业务分离
  2. 资源隔离:专用Worker处理
  3. 弹性扩展:基于Redisson的分布式能力
  4. 内存优化:流式处理+分片上传

未来优化方向

  1. 增加导出任务优先级机制
  2. 实现动态Worker扩缩容
  3. 添加导出失败自动重试
  4. 完善导出监控告警体系

希望这篇实战经验能帮助遇到类似问题的开发者!如果对实现细节有疑问,欢迎在评论区交流讨论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2377160.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Delphi 12.3调用Chrome/edge内核实现DEMO源码

DELPHI使用调用Chrome/Edge内核浏览器&#xff0c;虽然旧的WebBrowser也还可以用&#xff0c;但大势所趋&#xff0c;新版的已经不需要使用第三方的组件了&#xff0c;算是全内置的开发了&#xff0c;不废话 Unit1 源码 Form 源码 unit Unit1;interfaceusesWinapi.Windows, W…

GitDiagram - GitHub 仓库可视化工具

GitDiagram - GitHub 仓库可视化工具 项目链接&#xff1a;https://github.com/ahmedkhaleel2004/gitdiagram 将任何 GitHub 仓库转换为交互式架构图&#xff0c;只需替换 URL 中的 hub 为 diagram。 ✨ 核心功能 即时可视化&#xff1a;将代码库结构转换为系统设计/架构图…

【Linux】基于虚拟机实现网络的管理

通过学习我们需要掌握&#xff1a;IP 的配置、子网掩码、网关、DNS 服务器】 一、配置虚拟机的IP地址 1. 查看虚拟机 IP 地址&#xff08;可以看到三个地址&#xff09; ip a&#xff08;即ip address show&#xff09; 其中可以看到&#xff1a; Linux系统识别的以太网接口…

QT 使用QPdfWriter和QPainter绘制PDF文件

QT如何生产pdf文件&#xff0c;网上有许多文章介绍&#xff0c;我也是看了网上的文章&#xff0c;看他们的代码&#xff0c;自己琢磨琢磨&#xff0c;才有了本编博客&#xff1b; 其他什么就不详细说了&#xff0c;本篇博客介绍的QPdfWriter和QPainter绘制PDF文件&#xff1b;…

linux - 权限的概念

目录 用户权限 超级用户与普通用户的区别 超级用户&#xff08;root&#xff09;&#xff1a; 普通用户&#xff1a; 切换用户身份 使用sudo执行高权限命令 用户管理 用户组管理 文件权限 文件访问者类别 基本权限 权限表示方法 权限修改 chmod chown chgrp u…

【Vue】CSS3实现关键帧动画

关键帧动画 两个重点keyframesanimation子属性 实现案例效果展示&#xff1a; 两个重点 keyframes 和 animation 作用&#xff1a;通过定义关键帧&#xff08;keyframes&#xff09;和动画(animation)规则&#xff0c;实现复杂的关键帧动画。 keyframes 定义动画的关键帧序列…

AD 多层线路及装配图PDF的输出

装配图的输出&#xff1a; 1.点开‘智能PDF’ 2. 设置显示顶层&#xff1a; 设置显示底层&#xff1a; 多层线路的输出 同样使用‘智能PDF’

MultiTTS 1.7.6 | 最强离线语音引擎,提供多音色无障碍朗读功能,附带语音包

MultiTTS是一款免费且支持离线使用的文本转语音&#xff08;TTS&#xff09;工具&#xff0c;旨在为用户提供丰富的语音包选项&#xff0c;实现多音色无障碍朗读功能。这款应用程序特别适合用于阅读软件中的离线听书体验&#xff0c;提供了多样化的语音选择&#xff0c;使得听书…

基于自校准分数的扩散模型在并行磁共振成像中联合进行线圈灵敏度校正和运动校正|文献速递-深度学习医疗AI最新文献

Title 题目 Joint coil sensitivity and motion correction in parallel MRI with aself-calibrating score-based diffusion model 基于自校准分数的扩散模型在并行磁共振成像中联合进行线圈灵敏度校正和运动校正 01 文献速递介绍 磁共振成像&#xff08;MRI&#xff09;…

OCR发票识别API实现

OCR发票识别API实现 1. 阿里云OCR发票识别2. Tesseract OCR3. 利用java调用大模型进行识别4. 飞桨PaddleOCR 1. 阿里云OCR发票识别 阿里云OCR发票识别 示例&#xff1a; 接口&#xff1a;https://dgfp.market.alicloudapi.com/ocrservice/invoice 参数&#xff1a;{"img&…

实战案例:采集 51job 企业招聘信息

本文将带你从零开始&#xff0c;借助 Feapder 快速搭建一个企业级招聘信息数据管道。在“基础概念”部分&#xff0c;我们先了解什么是数据管道和 Feapder&#xff1b;“生动比喻”用日常场景帮助你快速理解爬虫组件&#xff1b;“技术场景”介绍本项目中如何使用代理等采集策略…

从AlphaGo到ChatGPT:AI技术如何一步步改变世界?

从AlphaGo到ChatGPT&#xff1a;AI技术如何一步步改变世界&#xff1f; 这里给大家分享一个人工智能学习网站。点击跳转到网站。 https://www.captainbed.cn/ccc 前言 在科技发展的历史长河中&#xff0c;人工智能&#xff08;AI&#xff09;技术无疑是最为璀璨的明珠之一。从…

AI 编程革命:腾讯云 CodeBuddy 如何重塑开发效率?

引言 在传统开发流程中&#xff0c;开发者常需依赖 SDK 文档或反复调试来获取云资源信息。而随着 AI 技术爆发式发展&#xff0c;腾讯云推出的 CodeBuddy 正以对话式编程颠覆这一模式 —— 只需自然语言描述需求&#xff0c;即可直接生成可执行代码。作为腾讯混元大模型与 Dee…

星海智算云平台部署GPT-SoVITS模型教程

背景 随着 GPT-SoVITS 在 AI 语音合成领域的广泛应用&#xff0c;越来越多的个人和团队开始关注这项前沿技术。你是否也在思考&#xff0c;如何快速、高效地部署并体验这款强大的声音克隆模型&#xff1f;遗憾的是&#xff0c;许多本地部署方案不仅配置复杂&#xff0c;而且对…

15:00开始面试,15:06就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到4月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

20250515通过以太网让VLC拉取视熙科技的机芯的rtsp视频流的步骤

20250515通过以太网让VLC拉取视熙科技的机芯的rtsp视频流的步骤 2025/5/15 20:26 缘起&#xff1a;荣品的PRO-RK3566适配视熙科技 的4800W的机芯。 1080p出图预览的时候没图了。 通过105的机芯出图确认 荣品的PRO-RK3566 的硬件正常。 然后要确认 视熙科技 的4800W的机芯是否出…

UE5.3 C++ 房屋管理系统(二)

三.当房屋生成成功&#xff0c;我们就需要把TMap里的数据存到数据库里。不然一点停止运行&#xff0c;就会所以数据都不见了。这里使用DataTable来存储。 1.DataTable是UE常用的表&#xff0c;虽然不是专门用来存档的&#xff0c;但也可以这么用。 DataTable表&#xff0c;实…

VSCode1.101.0便携版|中英文|编辑器|安装教程

软件介绍 Visual Studio Code是微软推出的一个强大的代码编辑器&#xff0c;功能强大&#xff0c;操作简单便捷&#xff0c;还有着良好的用户界面&#xff0c;设计得很人性化&#xff0c;旨在为所有开发者提供一款专注于代码本身的免费的编辑器。 软件安装 1、 下载安装包…

Linux系统发布.net core程序

前端 前端用的Vue3&#xff0c;发布的话需要Nginx下载安装Nginx 麒麟&#xff1a;这里我麒麟用的是桌面版&#xff0c;我直接把操作流程写在下面&#xff0c;写的比较简单&#xff0c;具体的可以具体搜这一块内容学习一下。打包vue程序&#xff0c;通过MobaXterm将打包后的程序…

极新携手火山引擎,共探AI时代生态共建的破局点与增长引擎

在生成式AI与行业大模型的双重驱动下&#xff0c;人工智能正以前所未有的速度重构互联网产业生态。从内容创作、用户交互到商业决策&#xff0c;AI技术渗透至产品研发、运营的全链条&#xff0c;推动效率跃升与创新模式变革。然而&#xff0c;面对AI技术迭代的爆发期&#xff0…