SpringBoot中XXL-JOB实现灵活控制的分片处理方案

❃博主首页 : 「码到三十五」 ,同名公众号 :「码到三十五」,wx号 : 「liwu0213」
☠博主专栏 : <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关>
♝博主的话 : 搬的每块砖,皆为峰峦之基;公众号搜索「码到三十五」关注这个爱发技术干货的coder,一起筑基


场景

一个应用需要支持大量数据的批处理任务,要求:

  1. 并行处理能力:应用需能够同时处理多个数据块,即实现并行处理。
  2. 灵活的并发控制:可以灵活调整并行处理的任务数量,以确保资源利用最大化且不过载。
  3. 均衡负载分配:应将任务均匀分配到不同的服务器节点上,以平衡各节点的负载,避免单点压力过大。

解决思路

因为需要并行处理同一张数据表里的数据,所以比较自然地想到了分片查询数据,可以利用对 id 取模的方法进行分片,避免同一条数据被重复处理。那XXL-JOB 的路由策略「分片广播 & 动态分片」很贴合这种场景」来调度定时任务;

实现DEMO

SpringBoot环境下,我们集成xxl-job来实现上述方案。

SpringBoot如何集成xxl-job查看官网即可,这里不再叙述,下面看下分片调度的代码:

1.xxl-job调度管理页面配置分片调度任务

路由策略选择: 分片广播

2. 编写task代码:

要获取分片总数和当前分片序号,作为参数传给sql语句:

java 复制代码
	@Resource
    private OrderDataMapper orderDataMapper;
	
    @XxlJob("orderDataStatusTask")
    public void orderDataStatusTask() {
		// 计时器
        Stopwatch timer = Stopwatch.createStarted();
        
		// 获取xxl-job的localThread中的总的分片数和当前分片
		OrderDataParam param = new OrderDataParam();
        param.setShardIndex(XxlJobHelper.getShardIndex());
        param.setShardTotal(XxlJobHelper.getShardTotal());
        // 其他参数设置,略了....
        
		// 根据分片数拉取当前分片的数据
        List<OrderData> orderDataList = orderDataMapper.getInitStatusOrder(param);
        XxlJobHelper.log("获取待处理订单数据:分片号={},数据量={},总分片数={}", XxlJobHelper.getShardIndex(), orderDataList.size(), XxlJobHelper.getShardTotal());
        if (CollUtil.isEmpty(orderDataList)) {
            return;
        }
        // 处理逻辑,略了....
        
        XxlJobHelper.log("当前分片({})处理完成,耗时={}秒", XxlJobHelper.getShardIndex(), timer.stop().elapsed(TimeUnit.SECONDS));
    }

这里服务启动了4个实例,总分片数ShardTotal就是4,每个实例的ShardIndex分别是0,1,2,3

3. mybatis中编写sql语句

根据分片总数和当前分片数据对Id哈希取模, 这里做了两次hash,主要作用是用id最后一位hash方便直接看出数据被哪个分片调度了。

java 复制代码
	// 获取未处理的订单数据
	// 根据id末位数取hash后分片拉取
	<select id="getInitStatusOrder" parameterType="com.xxx.OrderDataParam"
            resultType="com.xxx.OrderData">
			select id,order_no,customer_code,
            from tt_order_data t
            where t.status = 0
				  and t.fail_count <![CDATA[ < ]]> #{retryCount}
				  and t.update_time <![CDATA[ >= ]]> #{lastUpdateTime}
				  and mod(mod(t.id, 10) , #{shardTotal}) = #{shardIndex}
			limit 0,200	
	</select>	
4.最后看下调度日志

同一次调度任务,4个实例个调度一次,并且拉取到各自部分的数据进行处理:

第3个实例的调度日志:

java 复制代码
	    2024-09-25 08:31:40 [com.xxl.job.core.thread.JobThread#run]-[130]-[Thread-144] 
		----------- xxl-job job execute start -----------
		----------- Param:{"lastHoursAgoModify":4,"rows":3000,"lastMonthAgoCreate":6,"retryCount":1}
		2024-09-25 08:31:40 [com.xxx.xxxx#orderDataStatusTask]-[47]-[Thread-144] 获取待处理订单数据:分片号=3,数据量=100,总分片数=4
		2024-09-25 08:31:41 [com.xxx.xxxx#orderDataStatusTask]-[53]-[Thread-144] 当前分片(3)处理完成,耗时=1秒
		2024-09-25 08:31:41 [com.xxl.job.core.thread.JobThread#run]-[176]-[Thread-144] 
		----------- xxl-job job execute end(finish) -----------
		----------- Result: handleCode=200, handleMsg = null
		2024-09-25 08:31:41 [com.xxl.job.core.thread.TriggerCallbackThread#callbackLog]-[197]-[xxl-job, executor TriggerCallbackThread] 
        ----------- xxl-job job callback finish.

第4个实例的调度日志:

java 复制代码
	    2024-09-25 08:31:40 [com.xxl.job.core.thread.JobThread#run]-[130]-[Thread-144] 
		----------- xxl-job job execute start -----------
		----------- Param:{"lastHoursAgoModify":4,"rows":3000,"lastMonthAgoCreate":6,"retryCount":1}
		2024-09-25 08:31:40 [com.xxx.xxxx#orderDataStatusTask]-[47]-[Thread-144] 获取待处理订单数据:分片号=4,数据量=80,总分片数=4
		2024-09-25 08:31:41 [com.xxx.xxxx#orderDataStatusTask]-[53]-[Thread-144] 当前分片(4)处理完成,耗时=1秒
		2024-09-25 08:31:41 [com.xxl.job.core.thread.JobThread#run]-[176]-[Thread-144] 
		----------- xxl-job job execute end(finish) -----------
		----------- Result: handleCode=200, handleMsg = null
		2024-09-25 08:31:41 [com.xxl.job.core.thread.TriggerCallbackThread#callbackLog]-[197]-[xxl-job, executor TriggerCallbackThread] 
        ----------- xxl-job job callback finish.

关注公众号码到三十五获取更多技术干货 !

相关推荐
浅念-4 小时前
一文吃透Git:本地操作|冲突处理|远程协作|GitFlow工作流详解
大数据·git·elasticsearch·搜索引擎·gitflow
Bs_MoneyMagnet4 小时前
基于springboot+vue的医疗健康便民服务平台的设计与实现 源码+文档
java·vue.js·spring boot·后端·spring
小王毕业啦4 小时前
2011-2024年 各地级市养老服务信息面板数据 xlsx
大数据·人工智能·数据挖掘·数据分析·社科数据·实证分析·经管数据
loser.with.m6 小时前
【AgentScope 2.0】05-从数据库配置到可运行 Agent:十个 Builder 开关怎么把一行 JSON 变成 HarnessAgent
人工智能·spring boot·ai
宽海智能仓储物流6 小时前
航发自动化立体库异构系统改造:宽海智能30天联调技术全解析
运维·数据仓库·自动化
行百里er7 小时前
Spring Insight 里收到的 Span 是怎么存下来的
spring boot·spring·监控
Mr数据杨9 小时前
餐厅评分预测实战案例 从结构化特征到回归建模落地
人工智能·数据分析·kaggle竞赛
xcl092510 小时前
智慧健身场馆系统开发实战:从架构设计到核心模块落地指南
java·spring boot
vx-程序开发10 小时前
【计算机毕设】基于Spring Boot的古城景区管理系统88564
java·数据库·spring boot·后端·spring·elasticsearch·课程设计
czhc114007566310 小时前
2026-09-11 一日综合:树的父链、git 概念、三方死锁、静默失败
大数据·git·elasticsearch