考拉定时任务框架kSchedule

此文已由做者杨凯明受权网易云社区发布。
html

欢迎访问网易云社区,了解更多网易技术产品运营经验。java


1.背景spring

目前项目中使用的定时任务框架存在下面这些问题
数据库

  • 没有统一的定时任务管理平台缓存

目前项目中使用定时任务的方式比较混乱,有部分系统使用了cron插件,有部分系统直接使用的spring task注解配置,没有一个统一的管理平台。使用cron插件的定时任务的配置集成在ms后台,管理页面比较简陋,须要一个更加友好、功能更加完善的管理系统,专门负责定时任务的管理,包括定时任务的建立、修改、删除、触发、查看历史等
服务器

  • 对每一个定时任务没有完善的监控网络

目前项目中没有对定时任务的监控,没法知道定时任务的执行状况和执行时间;当定时任务没有触发时没有告警;无法查看定时任务的执行历史状况
架构

  • 单点问题并发

目前使用spring task或quartz来作定时任务的系统,都须要手动指定运行定时任务的机器,这样会致使某台机器负载很高,而且若是这台机器宕机了则定时任务都不会执行
框架

  • 重复执行问题

有些定时任务自己不是幂等的,若是重复执行的话会有不少问题,好比短信的定时发送等;目前cron出现过zk断开后,致使定时任务被重复执行的状况

针对这些问题,须要设计一种能解决上述问题的新框架


2.设计

设计目标:

  1. 定时任务统一配置、统一管理

  2. 支持动态修改任务状态,动态暂停/恢复任务,即时生效

  3.  减小使用方的限制依赖

  4.  定时任务不遗漏、不重复的被执行

  5. 支持任务分片并发执行

  6. 完善的监控、统计功能


整个框架分为四部分:

  1. 调度服务器管理平台:负责定时任务的配置和管理,并定时进行任务的分配;获取每次任务执行的结果进行统计

  2. 任务执行器:经过心跳更新服务器信息;获取配置的任务信息定时执行任务,并根据任务执行状况上报执行结果

  3.  zk集群:存储任务配置信息和服务器节点信息;提供分布式协调服务

  4. 数据库:记录任务的每次执行状况,用于监控和统计

 

架构部署图以下:

ZK节点图:

触发类型:

  • 定时触发:经过定时任务框架与cron表达式定时触发

  • 手动触发:经过kschedule平台触发(1.按分配信息触发;2.指定一台机器执行)

  • 启动触发:应用启动时触发(如加载初始化本地缓存)

  • RPC触发:经过dubbo接口触发


任务类型:

  • 都不执行(只需人为去触发,使用场景较少)

  • 全部的机器上只有一台执行:该产品下全部注册上来的机器只会选择一台来执行

  • 全部机器都执行:该产品下全部注册上来的机器都会执行该任务

  • 在指定的机器上所有执行:被选择的机器都会执行该任务

  • 指定的机器上只有一台执行:被选择的机器中只会有一台会执行该任务

  • 任务分片执行(下面解释)


不重复执行策略及异常整理

  • 任务状态变为DOING状态后,备用机器再也不监放任务,认为任务已经有机器执行,如执行的机器在任务执行时挂掉,则形成任务遗漏执行。

  • 如主机器500ms内没有将任务变为DOING状态,则备用机器恢复抢锁进行任务执行,没抢到锁的机器继续监放任务状态。


  1. kschedule服务端挂了:不影响任务执行

  2. 执行前服务器网络断开:由备机执行

  3. 执行前服务器挂掉:由备机执行

  4. 执行中服务器网络断开:任务正常执行,可能会报警遗漏执行

  5. 执行中服务器挂掉:任务不能正常执行,会报警

  6. zk挂掉:任务不能正常(zk进程监控)

  7. 执行分配的机器全挂掉:任务不能正常执行,会报警


不遗漏执行策略及异常整理

  • 任务状态变为DOING状态后,备用机器继续监放任务,直到任务状态变动为DONE时,监听取消。

  • 如主机器在DOING状态后挂掉或者失去与ZK的链接,则备用机器恢复抢锁进行任务执行,没抢到锁的机器继续监放任务状态,可能会形成任务重复执行。


  1. kschedule服务端挂了:不影响任务执行

  2. 执行前服务器网络断开:由备机执行

  3. 执行前服务器挂掉:由备机执行

  4. 执行中服务器网络断开:由备机执行,可能重复执行

  5. 执行中服务器挂掉:由备机执行

  6. 执行中任务执行超时:由备机执行,可能重复执行

  7. zk挂掉:任务不能正常( zk进程监控)

  8. 执行分配的机器全挂掉:任务不能正常执行,会报警


分片任务:

分片任务即将一个任务按必定规则拆成多个子任务在多台机器上的多个线程中并行执行。

须要实现IScheduleShardingTask接口,

例子1:服务器有5台

分片信息:0,1,2,3,4,5,6,7,8,9

分片最大线程数:10

分片获取数据的数量:100

则kschedule会将任务进行分片,每台机器分配到2个执行线程,每一个线程执行1个分片,每一个分片拉取100条数据。

每一个线程回调到selectItems方法上的参数为selectItems(null,10,[0],100);

selectItems:应用系统在接口实现中根据分片传入的参数去DB拉取待处理的数据。

execute:应用系统在接口实现中根据selectItems方法拉取的数据进行数据处理。

例子2: 服务器有5台

分片信息:a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z

分片最大线程数:10

分片获取数据的数量:1000

则kschedule会将任务进行分片,每台机器分配到2个执行线程,每一个线程执行3个分片(部分是2个分片),每一个分片拉取1000条数据。

每一个线程回调到selectItems方法上的参数为selectItems(null,26,[a,b,c],1000);

selectItems:应用系统在接口实现中根据分片传入的参数去DB拉取待处理的数据。

execute:应用系统在接口实现中根据selectItems方法拉取的数据进行数据处理。


/**
 * 分片任务定义接口,业务方需实现该接口才能使用分片功能
 * @author hzyangkaiming
 *
 */public interface IScheduleShardingTask {    /**
     * 拉取业务数据的方法
     * @param parameter 自定义参数
     * @param shardingCount 任务分片总数
     * @param shardingIndexs 分配到的任务分片
     * @param limit 每次获取数据的数量
     * @return 待处理的数据
     * @author yangkaiming
     * @since 2016年5月16日
     */
    public List selectItems(String parameter,int shardingCount,List shardingIndexs,int limit);    /**
     * 执行指定的任务
     *
     * @param items 处理的数据
     * @return 成功/失败
     * @author yangkaiming
     * @since 2016年5月16日
     */
    public boolean execute(T[] items);

执行日志:

执行日志会在框架调度业务方法时进行记录,写到ZK,kschedule平台会收集并清理zk。

用户能够在kschedule平台查询任务执行状况,包括执行时间状况,任务每次触发执行的服务器等信息


3.监控

1.根据cron表达式及任务执行日志,对任务漏执行、重复执行、超时执行等进行准实时报警。

2.任务执行失败(业务方法未捕获的Exeption)报警,并推送错误堆栈,帮助定位解决问题。

2.支持很是规节假日短信报警,平日上班时间popo、stone报警,下班时间popo、stone、短信报警。


4.实践

通过一年的推广及优化,考拉目前各系统定时任务已经基本完成切换,并稳定运行于kschedule平台,固然也有很多坑:


坑1:业务方法卡住

背景:定时任务运行时会占有该任务的分布式锁,若是任务挂住会形成后面每次触发任务都会忽略执行,防止重复执行。

问题: http,ftp等外部调用相关业务定时任务出现任务挂住的问题

实时处理:任务出现超时并长期运行中,则优先打印堆栈信息,保留现场,并根据业务方评估是否人工去zk释放锁,让任务先跑起来。

后期处理:业务放根据堆栈等信息定位卡主缘由进行优化(主要以超时时间为主),平台增长实时zk锁查询,判断任务是否占用锁,并增长管理员删锁按钮,提高运维能力。


坑2:新上线分片任务重复执行并执行紊乱

背景:分片任务会根据分配信息异步起线程(有默认线程池)进行处理,而且单个分片没有加分片的分布式锁。业务放上线10个分片任务,每一个分片任务10个线程,总共4台机器,触发时间都是每分钟的0秒,默认线程池5个初始线程,1000的队列,队列满扩到20个线程

问题:业务系统上线,业务系统ftp调用超时问题也比较多,形成分片任务执行彻底紊乱,执行日志无参考性,业务方法出现重复执行

实时处理:通过初步判断,根据业务方分片任务数量及线程量,优先加大线程池提升处理能力,紧急上线,但不能彻底解决问题。

后期处理:修改默认线程池策略,去掉缓冲队列,线程不够直接扩,最大200个,超过150个报警;由于业务方须要高频率调度这些分片任务,加上与ftp调用等执行时间不可控因素,所以增长单个分片的分布式锁,防止重复执行,而且极大下降线程占用量。

那么如今:

kschedule平台目前每日的任务执行次数平均在20+w次。

网易金融也已搭建本身的kschedule环境,并在线上使用中。

考拉订单流推送、申报单推送、物流信息等供应链相关业务已接入分片任务,极大提升了业务吞吐量、下降DB压力,提高了通关效率。

支撑双11、黑5、双十二等大促,高峰期统一暂停非关键定时任务,让出系统资源,提升业务系统稳定性。


5.计划

近:任务执行时间TOP统计,方便业务系统优化定时任务性能等;

远:能够根据考拉的业务须要,增长非java方法调度功能等;

欢迎考拉的兄弟姐妹贡献需求及改进点



网易云免费体验馆,0成本体验20+款云产品! 

更多网易技术、产品、运营经验分享请点击


相关文章:
【推荐】 Android TV 开发 (1)

相关文章
相关标签/搜索