一、整体架构设计
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实现执行器自动扩缩容
-
-
开关降级:
-
增加业务开关,高峰期可降级处理
-
实现慢任务熔断机制
-