前言
两篇写的很好的关于分布式事务的文章:
基于数据最终一致性的解决方案,无非就是 消息表+mq+定时扫表+幂等。
那么有没有一个轻量级的组件,可以支持将大事务切割成小事务,每个小事务自动重试+幂等;同时又不依赖于redis, 不依赖于mq,也不需要额外单独部署,只要引入就可以实现?
简介
yy-job,一个轻量级的分布式链式异步任务组件,spring-boot项目直接引入即可使用,无需部署依赖其他第三方的中间件。
支持动态创建链式任务,支持任务按照默认策略进行自动重试和幂等,支持控制台管理和告警等。
当前版本支持mysql和sqlserver,后续将支持oracle,db2
开发环境控制台体验 :http://120.26.212.160:9091/yyJob/console/jobListPage
测试数据创建: http://120.26.212.160:9091/boot/index
源码 gitee: https://gitee.com/the_source_of_the_abyss/yy-job
ps: 此组件参考了前司内部的async-job组件。该async-job组件在事业部得到了广泛的应用。作者参考了该组件的设计思路,对其进行重构之后命名为yy-job。
功能/特性
1 链式任务创建和处理机制
yy-job 提供了强大的链式任务创建和处理机制,允许在一个任务下设置多个步骤,每个步骤都可以指定执行顺序。这使得长事务可以被拆分成小事务,并按照预定义的顺序依次执行,提高了任务的可控性和灵活性。
2 默认策略的重试机制
对于任务执行失败的情况,yy-job 提供了默认的重试策略。如果任务在创建时间内未能完成,或者重试次数不超过10次,将按照以下时间间隔进行重试:0分, 5分, 10分, 30分, 1小时, 2小时, 6小时, 12小时, 1天, 2天, 3天。
3 分布式事务的最终一致性
通过链式任务机制,yy-job 实现了分布式事务的最终一致性。即使在任务执行的过程中发生异常,系统也能够保证数据的一致性和可靠性。
4 任务分组与并发处理
yy-job 支持任务分组,每个分组可以自定义自己的并发处理数量。这个特性确保不同业务的任务不会因为数据量而互相干扰,提高了系统的整体性能和稳定性。
5 延迟任务支持
yy-job 支持创建延迟任务,用户可以指定任务的首次执行时间为未来的某个时间,以满足特定的业务需求。
6 任务锁定时间
为了避免执行时间较长的任务被其他执行器执行,yy-job 支持设置任务的锁定时间。这个特性确保任务在锁定时间内只能由一个执行器执行,防止并发执行导致的问题。
7 可视化控制台
yy-job 配备了直观的可视化控制台,用户可以轻松地查看任务的运行情况。控制台提供了关闭、重启、跳过等操作,使得任务的管理更加便捷。
8 数据库支持
yy-job 目前支持 MySQL 和 SQL Server 数据库。未来版本将进一步扩展支持 Oracle 和 DB2,以满足更广泛的数据库需求。
环境要求
JAVA
请使用 Java 8 及其以上版本
Maven
建议使用 Maven 3.5.0 及其以上版本
Spring-boot
spring-boot亲测2.7.11版本。其他版本请各自调试。
快速入门
1. 获取以下源码
https://gitee.com/the_source_of_the_abyss/yy-job 仓库,下载源码
或者 git clone https://gitee.com/the_source_of_the_abyss/yy-job.git
2. 部署本地数据库
从/doc/db下获取对应数据库的ddl脚本进行部署
3. 修改配置文件
修改yy-job-boot项目下的yy-job-boot-database.properties文件里面的数据库配置
4. 启动spring-boot项目
启动YYJobBootApplication.java
5. 愉快的访问控制台
http://localhost:8080/yyJob/console/jobListPage
6. 创建测试数据。以下链接可以方便创建测试数据
http://localhost:8080/boot/index
7. 在控制台上观察任务执行结果。可以通过重启,关闭,跳过等按钮对任务进行管理
项目目录结构
本项目为maven项目,开发者获取源码之后,可以直接导入到ide中进行后续的开发
- doc/db ------包含不同数据库的建表语句
- yy-job-boot ------spring-boot的demo项目,演示了如何引入yy-job-core和yy-job-console
- yy-job-common ------yy-job的底层代码,数据库层/工具类
- yy-job-console ------yy-job的控制台项目,如果需要控制台功能则请引入
- yy-job-core ------yy-job的核心代码,任务配置,任务定时器等核心功能
集成流程
1. 数据库初始化
在如下目录/doc/db获取对应的数据库的初始化脚本
2. 在项目中引入yy-job的最新版
<!-- 核心,必须引入-->
<dependency>
<groupId>com.yy</groupId>
<artifactId>yy-job-core</artifactId>
<version>最新</version>
</dependency>
<!-- 可视化管理控制台,按需引入-->
<dependency>
<groupId>com.yy</groupId>
<artifactId>yy-job-console</artifactId>
<version>最新</version>
</dependency>
3. 引入yy-job的xml配置。以下为演示xml中引入,开发者可以根据自己spring-boot的情况选择注解或者xml引入
<!-- 引入yy-job-core里面的xml配置 -->
<import resource="yy-job-context.xml" />
<!-- 引入yy-job-console里面的xml配置,可视化管理控制台相关,按需引入 -->
<import resource="yy-job-console.xml" />
4. mybatis增加yy-job相关配置。以下为演示xml中引入,开发者可以根据自己spring-boot的情况选择具体的引入方式
<!-- ${jdbc.mybatis.config} 值根据数据库选择 mybatis/yy-mybatis-config-mysql.xml 或者 mybatis/yy-mybatis-config-sqlserver.xml -->
<bean id="SqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="yyDataSource" />
<property name="configLocation" value="classpath:${jdbc.mybatis.config}" />
</bean>
<!-- 增加扫描如下路径 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.yy.job.common.dao" />
</bean>
5. 在application.yml文件里面增加如下。如果不引入可视化控制台,则不用增加
#如果不引入可视化控制台,则不用增加
spring:
freemarker:
suffix: .ftl
6. 增加如下配置。
其中yy-job-config.xml为预定义的任务。如果预定义的任务的xml文件名为yy-job-config.xml,也可不用配置
yy-job.configPath=yy-job-config.xml
7. 增加样例 yy-job-config.xml样例。样例说明见配置项说明
<yyJobProject>
<!-- 模组1 -->
<moduleConfig moduleCode="module1" moduleName="任务模组1" jobWorkerSize="1">
<jobConfig jobCode="jobCode1" jobName="任务1">
<lockTime>15</lockTime>
<jobStepConfigs>
<jobStepConfig stepCode="jobTask1" stepName="步骤1">
<stepProcessBean>jobTask1</stepProcessBean>
<stepOrder>1</stepOrder>
</jobStepConfig>
<jobStepConfig stepCode="jobTask2" stepName="步骤2">
<stepProcessBean>jobTask2</stepProcessBean>
<stepOrder>2</stepOrder>
</jobStepConfig>
<jobStepConfigs>
</jobConfig>
</moduleConfig>
</yyJobProject>
8. 启动你的spring-boot项目, 愉快的访问链接
http://localhost:8080/yyJob/console/jobListPage
任务配置项说明
<yyJobProject>
<!-- 模组1 -->
<moduleConfig moduleCode="module1" moduleName="任务模组1" jobWorkerSize="1">
<jobConfig jobCode="jobCode1" jobName="任务1">
<lockTime>15</lockTime>
<jobStepConfigs>
<jobStepConfig stepCode="jobTask1" stepName="步骤1">
<stepProcessBean>jobTask1</stepProcessBean>
<stepOrder>1</stepOrder>
</jobStepConfig>
<jobStepConfig stepCode="jobTask2" stepName="步骤2">
<stepProcessBean>jobTask2</stepProcessBean>
<stepOrder>2</stepOrder>
</jobStepConfig>
<jobStepConfig stepCode="jobTask3" stepName="步骤3">
<stepProcessBean>jobTask3</stepProcessBean>
<stepOrder>3</stepOrder>
</jobStepConfig>
</jobStepConfigs>
</jobConfig>
</moduleConfig>
<!-- 模组2 -->
<moduleConfig moduleCode="module2" moduleName="任务模组2" jobWorkerSize="4">
<jobConfig jobCode="jobCode2" jobName="任务2">
<lockTime>15</lockTime>
<jobStepConfigs>
<jobStepConfig stepCode="jobTask1" stepName="步骤1">
<stepProcessBean>jobTask1</stepProcessBean>
<stepOrder>1</stepOrder>
</jobStepConfig>
<jobStepConfig stepCode="jobTask2" stepName="步骤2">
<stepProcessBean>jobTask2</stepProcessBean>
<stepOrder>2</stepOrder>
</jobStepConfig>
</jobStepConfigs>
</jobConfig>
</moduleConfig>
</yyJobProject>
节点 | 层级 | 必录 | 描述 |
---|---|---|---|
yyJobProject | 0 | 根节点,固定格式,无意义 | |
▷moduleConfig | 1 | 模块组,可以配置多个进行分组,互相不干扰 | |
▷▷moduleCode | 2 | 是 | 模块组code,唯一 |
▷▷moduleName | 2 | 是 | 模块组名称 |
▷▷jobWorkerSize | 2 | 模块组下面的任务的并行处理数量 | |
▷▷jobConfig | 2 | 任务,固定格式 | |
▷▷▷jobCode | 3 | 是 | 任务code,在同一个module下唯一 |
▷▷▷jobName | 3 | 是 | 任务名称 |
▷▷▷lockTime | 3 | 锁定时间。执行时间超过锁定时间会被重置重新启动。 默认锁定时间为60分钟 | |
▷▷▷▷jobStepConfigs | 4 | 步骤,固定格式 | |
▷▷▷▷▷jobStepConfig | 5 | 步骤,固定格式 | |
▷▷▷▷▷▷stepCode | 6 | 是 | 步骤code,在同一个任务下唯一 |
▷▷▷▷▷▷stepName | 6 | 是 | 步骤名称 |
▷▷▷▷▷▷stepProcessBean | 6 | 是 | 步骤对应的spring框架下的处理bean的名称 |
▷▷▷▷▷▷stepOrder | 6 | 步骤的顺序 |