XXL-JOB + 线程池优化超时订单关闭任务方案

一、整体架构设计

XXL-JOB调度中心 → 触发 → 执行器(多节点) → 线程池 → 批量处理订单关闭任务

二、具体实现步骤

1. 配置XXL-JOB任务

在XXL-JOB管理后台创建任务:

四、扩展优化方向

通过以上方案,可以将超时订单关闭任务的性能提升10倍以上,同时保证系统的稳定性和可靠性。

  • 任务描述:超时订单关闭任务

  • 调度类型:CRON调度(如:0 0/5 * * * ? 每5分钟执行一次)

  • 运行模式:BEAN模式

  • 路由策略:分片广播(充分利用集群资源)

  • 阻塞处理策略:丢弃后续调度

  • 2. 执行器核心代码实现

  • @Component
    public class CloseOrderJobHandler {
        
        private static final Logger logger = LoggerFactory.getLogger(CloseOrderJobHandler.class);
        
        // 自定义线程池配置
        private final ThreadPoolExecutor orderCloseExecutor = new ThreadPoolExecutor(
            10, // 核心线程数
            50, // 最大线程数
            60L, TimeUnit.SECONDS, // 空闲线程存活时间
            new LinkedBlockingQueue<>(1000), // 任务队列
            new ThreadFactoryBuilder().setNameFormat("order-close-pool-%d").build(),
            new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略
        
        @XxlJob("closeOrderJobHandler")
        public void closeOrderJobHandler() throws Exception {
            // 获取分片参数
            int shardIndex = XxlJobHelper.getShardIndex();
            int shardTotal = XxlJobHelper.getShardTotal();
            
            XxlJobHelper.log("开始处理超时订单关闭任务,当前分片: {}/{}", shardIndex, shardTotal);
            
            // 1. 查询待关闭订单ID列表(根据分片参数分片查询)
            List<Long> orderIds = queryTimeoutOrders(shardIndex, shardTotal);
            
            // 2. 使用线程池并发处理
            CountDownLatch latch = new CountDownLatch(orderIds.size());
            List<Future<Boolean>> futures = new ArrayList<>();
            
            for (Long orderId : orderIds) {
                futures.add(orderCloseExecutor.submit(() -> {
                    try {
                        return closeSingleOrder(orderId);
                    } finally {
                        latch.countDown();
                    }
                }));
            }
            
            // 等待所有任务完成
            latch.await(5, TimeUnit.MINUTES); // 设置合理超时时间
            
            // 3. 处理结果统计
            int successCount = 0;
            for (Future<Boolean> future : futures) {
                if (future.get()) {
                    successCount++;
                }
            }
            
            XxlJobHelper.log("订单关闭任务完成,总数: {}, 成功: {}, 失败: {}", 
                orderIds.size(), successCount, orderIds.size() - successCount);
        }
        
        private List<Long> queryTimeoutOrders(int shardIndex, int shardTotal) {
            // 根据分片参数查询待关闭订单ID
            // 示例SQL: SELECT id FROM orders 
            // WHERE status = '待支付' AND create_time < NOW() - INTERVAL 30 MINUTE
            // AND MOD(id, #{shardTotal}) = #{shardIndex}
            return orderMapper.selectTimeoutOrderIds(shardIndex, shardTotal);
        }
        
        private boolean closeSingleOrder(Long orderId) {
            try {
                // 1. 查询订单详情(带乐观锁版本号)
                Order order = orderMapper.selectByIdForUpdate(orderId);
                if (order == null || !"待支付".equals(order.getStatus())) {
                    return false;
                }
                
                // 2. 执行关闭操作
                int updateCount = orderMapper.closeOrder(orderId, order.getVersion());
                if (updateCount > 0) {
                    // 3. 记录关闭日志
                    orderLogService.logClose(orderId, "超时自动关闭");
                    
                    // 4. 释放库存等关联操作
                    inventoryService.unlockStock(orderId);
                    
                    // 5. 发送关闭通知(异步)
                    notifyService.sendOrderCloseMsg(orderId);
                    
                    return true;
                }
                return false;
            } catch (Exception e) {
                logger.error("关闭订单失败, orderId: {}", orderId, e);
                return false;
            }
        }
    }
  • 3. 线程池优化配置

  • 核心参数调优

    • 根据服务器CPU核心数设置核心线程数(建议N+1)

    • 最大线程数根据业务峰值设置

    • 队列大小根据业务容忍度设置

  • 监控与动态调整

  • // 添加线程池监控端点
    @Endpoint(id = "order-close-pool")
    public class OrderClosePoolEndpoint {
        
        @ReadOperation
        public Map<String, Object> metrics() {
            ThreadPoolExecutor executor = SpringContext.getBean(CloseOrderJobHandler.class).getOrderCloseExecutor();
            
            Map<String, Object> metrics = new HashMap<>();
            metrics.put("activeCount", executor.getActiveCount());
            metrics.put("poolSize", executor.getPoolSize());
            metrics.put("corePoolSize", executor.getCorePoolSize());
            metrics.put("maxPoolSize", executor.getMaximumPoolSize());
            metrics.put("queueSize", executor.getQueue().size());
            metrics.put("completedTaskCount", executor.getCompletedTaskCount());
            return metrics;
        }
    }

  • 三、性能优化关键点

  • 分布式分片处理

    • 利用XXL-JOB分片广播特性,将订单均匀分配到不同执行器节点

    • 每个节点再通过线程池并行处理

  • 多级并行化

    • 第一级:XXL-JOB多节点并行

    • 第二级:单节点多线程并行

    • 第三级:批量数据库操作

  • 资源控制

    • 通过线程池队列大小控制内存占用

    • 通过分页查询避免大结果集内存溢出

    • 设置合理的超时时间防止长时间阻塞

  • 监控告警

    • 监控线程池状态(活跃线程、队列大小等)

    • 记录任务执行指标(处理订单数、成功率等)

    • 设置失败率告警阈值

  • 异步化改造

    • 将库存释放、通知发送等操作改为异步

    • 使用MQ解耦

  • 缓存优化

    • 对频繁访问的订单数据加缓存

    • 使用Caffeine实现本地缓存

  • 弹性伸缩

    • 根据负载动态调整线程池参数

    • 结合K8s实现执行器自动扩缩容

  • 开关降级

    • 增加业务开关,高峰期可降级处理

    • 实现慢任务熔断机制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值