分布式事件调度框架tiger

一、背景

在后台,有很多业务场景需要定时处理一个任务,或在某件事情发生后处理一个任务。

比如,dw团队后台数据同步时,一般会每天凌晨某个时间点跑一次数据同步任务。这样的业务场景1(定时处理任务),很适合quartz来处理。

有另外一种业务场景2(某个事件发生后触发处理任务),比如你在12306上购买火车piao提交订单后,系统会提示你在30分钟内完成支付,不然订单会被取消。针对这个情况,用quartz的定时任务方案也容易解决,只要开发一个quartz任务a每隔一段时间(比如每分钟)去轮询订单表,进行订单支付状态判断,如果未支付且时间已经超过30分钟,则将订单取消。

但是,如果12306有个新的功能,希望对订单支付成功的乘客,在列车开车前1小时进行短信提醒。那按quartz的做法,就是再开发一个任务b去轮询订单信息表,对已支付的订单,且列车发车时间距当前时间小于1小时的,进行短信发送提醒。如果类似的附加任务越来越多,每次都需要开发一个定时任务去跑,任务就会变得越来越臃肿,越来越难以统一管理。而且,当任务数很多,一台机器处理不过来,需要多台机器同时处理时,任务的重复消费问题也开始体现出来。

为了解决上述问题,我们针对[业务场景2: 一件事情发生后需要触发另一个事情]的情况进行了抽象处理,提出一种 基于事件驱动的分布式异步调度架构

二、设计实现原理

tiger是一种分布式事件调度框架,用于解决触发式延时任务的业务场景,偏重于执行层面,同一种任务可以由多台机器同时执行,并能保证一条任务不被重复执行。 tiger的设计目标: - 基于事件驱动,一件事情发生后能指定下一个要做的任务,且能指定什么时候执行; - 高容错性,一个任务如果处理失败由任务本身来决定是否需要重新执行; - 集群环境下,同一个任务保证只执行一次,不被重复执行; 基于上述目标,tiger主要有以下三部分组成: 1. zk注册管理:用于管理应用机器的在线情况,进而对机器可执行的任务节点进行自适应分配,保证一个任务同一时间只会被一台机器消费; 2. 事件调度管理:用于每隔一定时间触发一次任务执行,并监听任务执行器的配置情况,一旦发生变化,即停止任务执行,重新设置后再触发任务执行; 3. 任务执行管理:用于管理本机所分配到的执行器节点,进而进行任务节点捞取、任务过滤等,并对任务的执行结果进行处理; tiger的整体架构如图所示:

输入图片说明

核心问题考虑: 1. 每一个任务的业务特性不一样,如何定义统一的业务参数; 2. 线上有多台机器,如何保证一个任务只会被一台机器执行; 3. 机器扩容或缩减时,在线的各个机器如何自适应分配各自能执行的任务,并保证不重复执行同一个任务; 针对业务参数,任务表的数据结构单独定义一个业务参数字段,约定为json格式;

针对多台机器同时处理任务的情况,在任务生成时通过hash计算得到虚拟节点node,再由任务机器选择虚拟节点执行,这样能保证一个任务只会被其中一台任务机器执行。如图所示: 虚拟节点任务

当一个任务task0过来时,根据hash取模计算得到该任务由虚拟节点v0处理,而tiger应用任务机器M0正好负责虚拟节点v0,v1的任务处理,这样task0就由任务机器M0处理,而不会被M1,M2处理。例举tiger-demo里的一个任务demoHandler,如下图: demoHandler

当机器扩容或缩减时,为了能让在线的任务机器自适应分配可以处理的任务节点,引入zookeeper,任务机器一启动就注册到zk集群,进而做到任务机器对虚拟节点任务处理的自适应管理,如图所示:

tiger-zookeeper

比如,当机器1挂掉时,zookeeper就会通知到机器2、3,此时虚拟节点就会重新分配,机器2负责node:0,1,2,机器3负责node:3,4,5,保证即使机器1挂掉的情况下,落在虚拟节点0,1上的任务也能被快速处理,避免任务堆积。

到此为止,所述的任务执行基本都是并行处理的,业务上,也有任务需要按时间顺序串行处理的情况。

如结婚商户通的合同上下线处理,原合同的到期下线时间: 2015-08-31 23:59:59,此时在这个时间点会执行一条合同任务a进行下线;

由于该商户与点评合作很好,所以续签了一份新的合同,上线时间: 2015-09-01 00:00:00,这个时间会执行一条合同任务b将其上线;

由于tiger默认一次性会获取200条任务,并交给线程池并发处理,此时任务a和b会同时被执行,由于多线程不保证时间顺序,可能导致任务b先执行完,然后任务a再执行。那么业务上,该商户明明续签了,但系统还是对其进行了下线(以最后一次执行为准)。

为了解决这个问题,tiger的任务执行策略支持并行和串行两种策略,默认为并行处理。如图:

tiger-chain

如果期望某个任务按串行处理,那么需要在任务实现类里加上一个注解:@ExecuteType(AnnotationConstants.Executor.CHAIN),比如以下的任务按串行执行:

@ExecuteType(AnnotationConstants.Executor.CHAIN)
public class ChainTestHandler implements DispatchHandler {
    @Override
    public DispatchResult invoke(DispatchParam param) throws Exception {
        Long taskId =  param.getTaskId();
        String jsonStr = param.getBizParameter();
        Map<String, String> paramMap = (Map<String, String>) JSON.parse(jsonStr);
        ...
    }
}

三、tiger使用说明

回归到背景里提到的业务场景2,如果让tiger来处理,就会很方便。用户提交生成订单,此时插入一条[订单取消任务],并指定执行时间30分钟后;用户订单支付成功后,此时插入一条[短信提醒任务],并指定执行时间开车前1小时。在订单取消任务里判断订单是否已支付,如果已经支付成功,那么无需处理并返回,如果订单尚未支付,则执行订单取消逻辑;在短信提醒任务里,判断该订单状态是否有效(如果退款或改签),如果有效则发送短信提醒。

tiger适合任何的 一件事情发生后需要触发另一个事情 的业务场景。

具体tiger的使用说明请看https://github.com/tkyuan/tiger

欢迎大家提建议,谢谢!

转载于:https://my.oschina.net/tkyuan/blog/675921

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值