天天看点

支付宝定时任务怎么做?三层分发任务处理框架介绍

作者:阿里开发者
本文将从单机定时调度开始,循序渐进地带领大家了解五福定制三层分发任务处理框架。

作者 | 金盛杰(司旭)

来源 | 阿里开发者公众号

1、背景介绍

技术同学对定时任务肯定不陌生。定时任务一般用来定时批量进行业务处理。支付宝卡包券到期提醒、删除过期失效券,五福大促批量给用户发放添福红包等场景,都是通过定时任务触发来完成的。

作者有幸参与了2023兔年五福大促的开发,主导完成了福气乐园分会场平分5000万大奖需求。通过学习并运用五福定制三层分发任务处理框架,最终平稳丝滑的完成了平分大奖需求任务。本文将从单机定时调度开始,循序渐进地带领大家了解五福定制三层分发任务处理框架。

2、定时任务分类

本文将定时任务分为单机和集群两大类别,其中单机又分为定时调度和定时调度加批处理框架,集群分为三层分发和五福定制三层分发任务处理框架。

2.1、单机任务

单机定时任务毫无疑问是在单台机器上运行的定时任务。在业务量级不大,没有进行分库分表时,往往单机定时任务即可满足业务需求。

从复杂度上来说,单机定时任务又可分为简单的定时调度和定时调度+批处理两种。

1、定时调度

在Spring中可以通过@Scheduled 来启用定时任务。触发的方式有两种,分别是:cron 表达式和 fixedRated类配置参数。常用的案例:

// cron表达式
@Scheduled(cron="0 0/30 9-17 * * ?") //按cron规则执行,朝九晚五工作时间内每半小时
@Scheduled(cron="0 0 12 ? * WED") //按cron规则执行,表示每个星期三中午12点

// fixedRated类配置
@Scheduled(fixedRate=5000) //上一次开始执行时间点后5秒再次执行;
@Scheduled(fixedDelay=3000) //上一次执行完毕时间点后3秒再次执行;
@Scheduled(initialDelay=1000, fixedDelay=2000) //第一次延迟1秒执行,然后在上一次执行完毕时间点后2秒再次执行;           
支付宝定时任务怎么做?三层分发任务处理框架介绍

定时调度往往用于业务处理流程比较简单的场景,比如定时生成简单报表,发送通知。对于复杂耗时的场景,处理效率不高,业务高峰期会积压大量待处理数据,影响业务。

2、定时调度+批处理

为了解决复杂耗时场景下定时调度效率不高的问题,可以引入批处理框架。定时调度与批处理框架相结合,可以大幅提高数据处理的效率,提升系统稳定性,保障业务稳定运行。

以Spring Batch批处理框架为例,任务处理流程如下:

支付宝定时任务怎么做?三层分发任务处理框架介绍

Spring Batch批处理框架将任务拆分成多个Step,同时每个Step里面又分为itemReader,itemProcessor, itemWriter。通过将任务分层细化,能够让多个阶段并行处理,提高任务处理效率。批处理框架结合定时调度框架,可以在单机情况下,对大量复杂的业务进行高效的批处理。

2.2、集群任务

在分库分表大业务流量情况下,单机定时任务已无法满足业务需求了,这时就产生了集群定时任务。在支付宝技术架构下,用户数据按照eid进行分库分表,同时进行Zone维度的隔离。此时单机定时任务无法对全量数据做处理,于是支付宝便有了自己的分布式任务调度中间件Antscheduler,配合三层分发任务处理框架,就可以对大量数据进行定时批量处理。

1、三层分发

支付宝定时任务怎么做?三层分发任务处理框架介绍

上图描述了三层分发实现定时任务处理的过程:

1.Antscheduler任务调度中间件按照配置好的规则,定时往消息中心投递消息。

2.消息中心将定时任务消息分别投递到每个Zone中的一台机器。

3.接收到消息的机器进入三层分发的第一层,即Splitor处理流程。通常是获取当前Zone的eid分片,比如00~24。

4.第一层Splitor处理完了之后,通过TR oneway的调用方式,在当前Zone对三层分发的第二层发起调用,即进入Loader处理流程。此时调用得到扩散,eid分片为00~24的情况下,会发起25次TR调用,即最多会进入当前Zone的25台机器进行Loader处理。

5.Loader通常是获取传递过来eid分片的数据。比如一台机器的Loader接收到eid为20,则该Loader从eid为20分片的DB获取100条待处理数据。

6.第二层Loader获取到待处理数据后,同样是通过TR oneway的调用方式,在当前Zone对三层分发的第三层发起调用,即进入Executor处理流程。此时调用进一步得到扩散,一个Loader获取的100条数据,此时会发起100次TR调用,即最多会进入当前Zone的100台机器进行Executor处理。

7.Executor通常是进行真正业务处理逻辑的地方。比如对每条数据做状态变更、发送eid维度消息等等。

三层分发能很好的将任务进行分层拆分扩散,充分利用机器资源,尽量做到负载均衡。但三层分发也存在一些缺陷,主要体现在以下几个方面:

1.定时调度间隔和间隔内能够处理的数据量很难完全匹配。调度间隔时间太长,机器资源没有得到有效利用,会导致处理效率低下,任务会积压;调度间隔时间太短,有可能会导致数据被重复捞取处理,为此要做额外的防重复处理逻辑。

2.无法做到平滑的任务处理。由于在Loader层获取要处理的任务数,交由Executor层执行时,并不能限制任务执行的qps,同时待处理任务数变多时,整个集群任务的qps就变得很高,对DB和其他外围系统来说,存在稳定性风险。

3.无法最大化利用集群机器资源。考虑到稳定性和高可用,设计上每个Zone是有A/B分组的,每个分组都能获取到本Zone的eid分片,所以配置Antscheduler调度规则时,通常只会选择Zone的A/B组中的一组开启任务调度。三层分发内部每个层级之间的TR调用又只能在本Zone同组内进行,A/B组之间无法进行TR调用,所以浪费了一半的机器资源。

2、五福定制三层分发

五福大促有很多业务场景都是需要通过定时任务来进行处理的,比如生肖卡提醒、AI年画提醒,福气乐园平分5000万大奖。五福大促对稳定性和可用性的要求是非常高的,为了解决三层分发处理框架缺陷带来的效率和稳定性风险,五福在三层分发基础上做了定制化改造,改造的目标主要有两点:

1)最大化利用集群机器资源。做到真正的负载均衡,同时也能够提升集群的任务处理容量。

2)平滑的任务处理。减少任务调用的尖刺,避免对DB和外部系统造成稳定性风险。

下面分别从优化目标的两点来进行阐述。

1、最大化利用集群机器资源

由于三层分发默认只会在同一个Zone的A/B组中开启一组,导致浪费了一半的机器。显而易见,要最大化利用集群机器资源,就需要让A/B组的机器都能够参与到任务处理当中。优化的步骤如下:

1.Antscheduler定时调度平台同时开启A/B分组调度。

2.增加任务配置,配置的目的是让A组的机器只处理奇数位eid、B组的机器只处理偶数位eid。

3.Splitor层根据任务配置,将本Zone全量eid进行分组,A组只处理奇数位eid,B组只处理偶数位eid。上面三步做完以后,就能让集群所有的机器都能参与到任务处理当中,从而最大化的利用了机器资源。

支付宝定时任务怎么做?三层分发任务处理框架介绍

以上图为例,Zone_01对应DB的eid分片为00~24,经过Splitor处理之后,Zone_01(A)组机器获得任务处理的eid都是奇数位,即01、03、...23;同理,Zone_01(B)组机器获得任务处理的eid都是偶数位,即00、02、...24。后续Loader、Executor处理都在本组内进行。通过把eid分片像A/B分组那样进行奇/偶分组,就能让所有机器都能够参与到任务处理当中。

下面是eid分组的核心代码:

/**
* 根据配置中心的dataFlag过滤
* 1、默认ALL不区分
* 2、ODD 表示仅分发奇数表号
* 3、EVEN 标识仅分发偶数表号
*
* @param eidList
*/
public void filteByDataFlag(List<String> eidList) {
    String dataFlag = SchedulerConfigDrmUtil.getIndexFilterFlag();
    int strategy = -1;
    if (StringUtil.equalsIgnoreCase("ODD", dataFlag)) {
        strategy = 1;
    } else if (StringUtil.equalsIgnoreCase("EVEN", dataFlag)) {
        strategy = 0;
    }
    if (strategy == -1) {
        // ALL
        return;
    }
    // filter
    Iterator<String> it = eidList.iterator();
    while (it.hasNext()) {
        String str = it.next();
        int index = NumberUtils.toInt(str, -1);
        if (index % 2 != strategy) {
            it.remove();
        }
    }
}           

通过代码可知,推送任务配置时,将A组机器的值推成“ODD”,B组机器的值推成“EVEN”,即可实现A/B组的所有机器同时执行定时任务的效果。

剩余60%,完整内容请点击下方链接查看:

支付宝定时任务怎么做?三层分发任务处理框架介绍

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。