一、项目介绍
Gobrs-Async 是一款功能强大、配置灵活、带有全链路异常回调、内存优化、异常状态管理于一身的高性能多线程并发编程和动态编排框架。为企业提供在复杂应用场景下动态任务编排的能力。针对于复杂场景下,异步线程复杂性、任务依赖性、异常状态难控制性;
二、解决什么问题
在开发复杂中台业务过程中,难免会遇到调用各种中台业务数据, 而且会出现复杂的中台数据依赖关系,在这种情况下。代码的复杂程度就会增加。如下图所示:
在请求调用各大中台数据时,难免会出现多个中台数据互相依赖的情况,现实开发中会遇到如下场景。
并行常见的场景 1 客户端请求服务端接口,该接口需要调用其他N个微服务的接口
譬如 请求我的购物车,那么就需要去调用用户的rpc、商品详情的rpc、库存rpc、优惠券等等好多个服务。同时,这些服务还有相互依赖关系,譬如必须先拿到商品id后,才能去库存rpc服务请求库存信息。最终全部获取完毕后,或超时了,就汇总结果,返回给客户端。
2 并行执行N个任务,后续根据这1-N个任务的执行结果来决定是否继续执行下一个任务,如用户可以通过邮箱、手机号、用户名登录,登录接口只有一个,那么当用户发起登录请求后,我们需要并行根据邮箱、手机号、用户名来同时查数据库,只要有一个成功了,都算成功,就可以继续执行下一步。而不是先试邮箱能否成功、再试手机号。
再如某接口限制了每个批次的传参数量,每次最多查询10个商品的信息,我有45个商品需要查询,就可以分5堆并行去查询,后续就是统计这5堆的查询结果。就看你是否强制要求全部查成功,还是不管有几堆查成功都给客户做返回
再如某个接口,有5个前置任务需要处理。其中有3个是必须要执行完毕才能执行后续的,另外2个是非强制的,只要这3个执行完就可以进行下一步,到时另外2个如果成功了就有值,如果还没执行完,就是默认值。
3 需要进行线程隔离的多批次任务。
如多组任务, 各组任务之间彼此不相关,每组都需要一个独立的线程池,每组都是独立的一套执行单元的组合。有点类似于hystrix的线程池隔离策略。
4 单机工作流任务编排。
5 其他有顺序编排的需求。
三、核心能力
四、框架设计
Gobrs-Async 在设计时,就充分考虑了开发者的使用习惯, 没有依赖任何中间件。对并发框架做了良好的封装。主要使用
CountDownLatch
、
ReentrantLock
、
volatile
等一系列并发技术开发设计。
任务触发器
任务流的启动者, 负责启动任务执行流
任务触发器
负责解析使用者配置的规则,同时于Spring结合,将配置的 Spring Bean 解析成 TaskBean,进而通过解析引擎加载成 任务装饰器。进而组装成任务树
任务启动器
负责通过使用解析引擎解析的任务树。结合 JUC 并发框架调度实现对任务的统一管理,核心方法有
trigger 触发任务加载器,为加载任务准备环境
任务加载器
负责加载任务流程,开始调用任务执行器执行核心流程
load 核心任务流程方法,在这里阻塞等待整个任务流程
getBeginProcess 获取子任务开始流程
completed 任务完成
errorInterrupted 任务失败 中断任务流程
error 任务失败
任务执行器
最终的任务执行,每一个任务对应一个
TaskActuator
任务的 拦截、异常、执行、线程复用 等必要条件判断都在这里处理
prepare 任务前置处理
preInterceptor 统一任务前置处理
task 核心任务方法,业务执行内容
postInterceptor 统一后置处理
onSuccess 任务执行成功回调
onFail 任务执行失败回调
任务总线
任务流程传递总线,包括 请求参数、任务加载器、 响应结果, 该对象暴露给使用者,拿到匹配业务的数据信息,例如:返回结果、主动中断任务流程等功能 需要任务总线(TaskSupport)支持
核心类图
五、落地场景
目前 Gobrs-Async 已经在京东商城商详团队落地使用,经受严酷的并发考验。对各种中台调用应对自如
通过 Gobrs-Async 管理中台接口请求 耗时任务请求 请求依赖关系等核心场景。充分利用CPU资源
六、规则示例
场景一
如图1-1
说明 任务A 执行完了之后,继续执行 B、C、D
配置
gobrs:
async:
rules:
- name: "ruleName1"
content: "A->B,C,D"
场景二
如图1-2
说明 任务A 执行完了之后执行B 然后再执行 C、D
配置
gobrs:
async:
rules:
- name: "ruleName1"
content: "A->B->C,D"
场景三
如图1-3
说明 任务A 执行完了之后执行B、E 然后按照顺序 B的流程走C、D、G。E的流程走F、G
配置
gobrs:
async:
rules:
- name: "ruleName1"
content: "A->B->C->D->G;A->E->F->G"
场景四
如图1-4
说明 这种任务流程 Gobrs-Async 也能轻松支持
配置
gobrs:
async:
rules:
- name: "ruleName1"
content: "A->B->C,D,E;A->H->I,J,K"
场景五
如图1-5
示例一
说明 A、B、C 执行完之后再执行D
配置
gobrs:
async:
rules:
- name: "ruleName1"
content: "A,B,C->D"
示例二
说明
A、B、C 任务任意一个执行完成,则立即执行任务D( 谁最快执行谁执行, 类似于任务流程竞争关系 ) 此时可以使用 配置关键字
:any
配置
gobrs:
async:
## :any 是关键字 表示任意 依赖的任务执行完成立即执行自己
rules:
- name: "ruleName1"
content: "A,B,C->D:any"
示例三
说明
A、B、C 任务任意一个执行完成,则立即执行任务D( 谁最快执行谁执行, 类似于任务流程竞争关系 ) 与示例不同的是, 如果 D拿到执行权后,会将自身所依赖的未完成的任务 强制中断执行(避免浪费资源,业务运行等) 此时可以使用 配置关键字
:exclusive
配置
gobrs:
async:
## :exclusive 是关键字
rules:
- name: "ruleName1"
content: "A,B,C->D:any:exclusive"
示例四
同示例二有点类似,在示例二的场景下,无法根据某一个任务的执行成功或者失败进行后续任务的处理,示例二完全根据线程调度执行的随机顺序进行执行,即谁先执行完 谁有资格继续往下执行,所以如果想 执行结果的条件 即:
task
方法返回
true
则立即执行,返回false则不执行的判断条件进行控制。那么就有以下的实现方式。
源代码下载地址:
https://gitee.com/dromara/gobrs-async.git
看到最后,如果这个项目对你有用,一定要给我点个「 在看和赞 」。