复杂业务场景下利用线程池和RocketMQ简化业务流程

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情

前言

在业务系统里面其实有很多复杂的业务场景,用传统的业务审批流比如active的形式太重,自己实现起来相对又比较复杂。最近调研比较好的一些轻量级流程引擎,比如[LiteFlow (yomahub.com)] 我们也有用。(liteflow.yomahub.com/)

但是在我们,最近项目中遇到这个业务场景也有些不太符合我们的流程,简单说下我们的实现和我自己的思考。

业务场景

image.png

业务场景,比如一个数据分析营销的场景,50w数据,按照上面节点串行执行有任务依赖关系,暂时没有并行节点。 节点规则,每个节点的耗时都很长,中间的节点可能调用第三方的api,api规则不一样,比如调用的时间段不一样,时间过了需要暂停调用,记录上一次调用位置,下一次需要接着执行,每个api限制的qps也不一样,到最终push到用户。还有一些累计和计费的规则。

任务的状态: 1、待执行 2、执行中 3、执行成功 4、 执行失败 5、任务终止
流程引擎节点状态:1、待执行 2、执行中 3、执行成功 4、执行失败 5、任务终止 6、暂停

流程设计中的难点

1、流程很长,涉及到多个第三方交互,执行时间长
2、异常流程设计, 重试机制
3、并发流控设计,在有限资源下面尽可能提高并发, 限流策略的考虑

最初一版,结果liteflow的流程如下图

image.png

触发任务的入口,通过定时任务触发,扫描主任务节点的状态,状态为执行中或者待执行的,进入流程引擎判断, 主流程下面各个节点的状态是否需要执行。

单个节点node的执行,先判断node的规则,比如第三方api调用不在时间范围内,将任务置为暂停状态,等定时任务回调。

但是这边有一个问题,比如node1节点调用第三方客户的api,客户api提供给我们固定的qps,我们多任务并行就存在并发的问题?不同客户api之间可以并行。

image.png

1、定时任务调用,线程池控制每次最大并发,当然前提需要判断最大任务数, 对于单个节点执行策略利用的RocketMQ消费者多线程。

/**
 * 撞库线程配置
 * 核心线程数: 10
 * 最大线程大小: 16
 * 阻塞队使用SynchronousQueue 做为等待队列(非公平策略) 它将任务直接提交给线程而不保持它们。当运行线程小于maxPoolSize时会创建新线程,否则触发异常策略
 * 任务的并发限制
 */
private static final ThreadPoolExecutor crowdWorkflowExecutor = ExecutorBuilder.create()
        .setCorePoolSize(8)
        .setMaxPoolSize(16)
        .useSynchronousQueue()
        .setAllowCoreThreadTimeOut(true)
        .setKeepAliveTime(1, TimeUnit.MINUTES)
        .setHandler(new ThreadPoolExecutor.AbortPolicy())
        .setThreadFactory(ThreadFactoryBuilder.create().setNamePrefix("node-workflow").build())
        .build();
复制代码

2、 RocketMQ Consumer多实例消费,结合线程池保证单个节点的并发可控

3、第三方api调用提供的接口,只允许串行调用,将每个节点拆分做为异步事件,通过redisson分布式锁,保证单个客户api调用的串行。

猜你喜欢

转载自juejin.im/post/7107250811436007454
今日推荐