先来思考以下业务场景的解决方案:支付系统每天凌晨1:00跑batch进行一日清算,最近一个月的电商每月1号为上月清算点类似的业务场景有很多,在30分钟内未能支付订单款项后,需要给客户发送短信提醒。商品发货成功后,需要给客户发送短信提醒。我们如何解决它们?为什么需要定时任务很多业务场景需要我们在特定的时刻做某项任务,而定时任务就是解决这个业务场景的。一般来说,系统可以使用消息传递来代替一些定时任务。两者有很多相似之处,可以互相替代对方的场景。比如上面下发成功发送短信通知客户的业务场景,我们可以在下发成功后将MQ消息发送到队列中,然后消费MQ消息发送短信。但是在某些场景下它们是不可互换的:时间驱动/事件驱动:内部系统一般可以用时间驱动,但是涉及到外部系统就只能用时间驱动了。如果怕拿外部网站的价格,每小时抓取一次进行批处理/逐条处理:对积累的数据进行批处理效率更高,在实时性要求高的情况下比消息中间件更有优势不需要。而且有些业务逻辑只能批量处理。实时/非实时:消息中间件可以实时处理数据,但在某些情况下不需要实时,如:vip升级系统内部/系统解耦:定时任务调度一般在里面系统和消息中间件可用于两个系统之间的定时任务框架。Stand-alonetimer:是一个定时器类,通过它可以配置指定的定时任务。TimerTask类是一个定时任务类,它实现了Runnable接口。缺点是如果不检查异常,线程就会被终止。ScheduledExecutorService:使用相对延迟或周期作为定时任务调度,缺点是没有绝对日期或时间。Spring定时框架:配置简单,功能多,如果系统使用单机,可以优先使用spring定时器分发Quartz:Java事实上的定时任务标准。但是Quartz关注的是定时任务而不是数据,没有基于数据处理的定制流程。Quartz虽然可以实现基于数据库的作业高可用,但是缺少分布式并行调度的功能TBSchedule:阿里巴巴早期开源的分布式任务调度系统。代码略显陈旧,使用定时器代替线程池进行任务调度。众所周知,定时器在处理异常方面存在缺陷。而且TBSchedule作业类型比较单一,只能是一种获取/处理数据的方式。elastic-job文档也严重缺乏:当当网开发的elastic分布式任务调度系统,功能丰富强大,使用zookeeper实现分布式协调,实现任务的高可用和分片。目前为2.15版本,可支持云开发Saturn:是唯品会自主研发的分布式定时任务调度平台。基于当当网的elastic-jobversion1开发,可以很好的部署在docker容器上。xxl-job:大众点评员工徐学礼于2015年发布的分布式任务调度平台,是一个轻量级的分布式任务调度框架。其核心设计目标是快速开发、易学、轻量、易扩展。分布式任务调度系统对比参与对比的备选系统方案:elastic——job(以下简称E-Job)和xxx-job(以下简称X-Job)项目背景及社区实力X-Job:Employees大众点评公司徐雪丽,3名贡献者; github有2470个star,1015个fork | QQ讨论群6 | 超过40家公司注册使用完整文档E-Job:当当开源,17位贡献者; github有2524个star,1015fork | QQ讨论群,1个源码讨论群 | 注册50多家公司 | 文档齐全 | 有明确的开发计划,支持集群部署X-Job:集群部署的唯一要求是:保证每个集群节点配置(db和登录账号等)要一致。调度中心通过db配置来区分不同的集群。执行器支持集群部署,提高调度系统的可用性,提高任务处理能力。集群部署的唯一要求是保证集群中各个executor的配置项“xxl.job.admin.addresses/调度中心地址”一致,executor根据这个执行自动注册等操作配置。E-Job:重写Quartz基于数据库的分布式功能,使用Zookeeper实现注册中心jobregistrationcenter:基于Zookeeper及其客户端Curator的全局职位注册控制中心。用于注册、控制和协调分布式作业执行。多节点部署时不能重复执行任务。X-Job:使用Quartz基于数据库的分布式功能E-Job :将任务拆分成n个任务项后,每个服务器分别执行分配的任务项。一旦有新服务器加入集群,或者已有服务器下线,elastic-job会在下一个任务开始前触发任务重分片,同时保持当前任务执行不变。日志可追溯X-Job:支持,有日志查询接口E-Job:调度过程中的重要事件可以通过事件订阅进行查询、统计和监控。Elastic-Job目前提供两种基于关系数据库的事件订阅方式来记录事件。监控告警X-Job:当调度失败时,会触发失败告警,比如发送告警邮件。任务调度失败时邮件通知的邮件地址,支持配置多个邮件地址,配置多个邮件地址时E-Job以逗号分隔:通过事件订阅,可以监控作业运行状态,监控作业服务器存活,监控最近dataprocessingSuccess,dataflowtypejobs(可以通过监控最近的数据处理成功次数来判断job流程是否正常,如果小于正常job处理的阈值,可以选择报警。),监控recentdataprocessingfailures(可以通过监控最近数据处理失败的次数来判断作业处理结果,如果大于0,可以选择报警。)弹性伸缩X-Job:利用Quartz的分布式函数基于在数据库上,如果服务器超过一定数量,就会对数据库造成一定的压力。E-Job:实现各种服务的注册、控制和协调,支持并行调度X-Job:多线程调度系统(默认10个线程)触发调度操作,保证调度执行准确无阻塞。E-Job:通过任务分片实现。一个任务被拆分成n个独立的任务项,分布式服务器并行执行各自分配的分片项。高可用策略X-Job:“调度中心”通过DB锁保证集群分布式调度的一致性,一次任务调度只会触发一次执行;E-Job:调度器的高可用是运行几个点到同一个ZooKeeper集群的Elastic-Job-Cloud-Scheduler实例实现的。ZooKeeper用于在当前主Elastic-Job-Cloud-Scheduler实例发生故障时执行领导者选举。一个集群由至少两个调度器实例组成,集群中只有一个调度器实例提供服务,其他实例处于“备用”状态。当实例出现故障时,集群会选举剩下的一个实例继续提供服务。失败处理策略X-Job:调度失败时的处理策略。策略包括:失败告警(默认),失败重试;E-Job:弹性扩缩容,在下一个作业运行之前重新分片,但是这个作业执行过程中,离线服务器分配的作业不会被重新分配。故障转移功能可以在当前作业运行期间使用空闲服务器来抓取孤立的作业碎片。故障转移功能也会牺牲一些性能。动态分片策略X-Job:分片广播任务在执行器维度进行分片,支持执行器集群动态扩展,动态增加分片数量,协调业务处理;它可以显着提高性能的大型业务操作任务处理能力和速度。执行器集群部署时,如果任务路由策略选择“分片广播”,将广播一个任务调度,触发对应集群中的所有执行器执行一个任务,同时传递分片参数;可根据分片参数制定分片任务;E-Job:支持多种分片策略,可自定义。分片策略默认包括三种分片策略:基于平均分配算法的分片策略,作业名哈希值的奇偶数决定IP升序降序算法的分值。Shardingstrategy,根据job名称的hash值轮换Job实例列表的分片策略,支持自定义分片策略。elastic-job的分片是通过zookeeper实现的。分片的分片由主节点分配。以下三种情况会触发分片算法在主节点上的执行:一个新的Job实例加入集群b。现有Job实例下线(如果leader节点下线,则先选举,再触发sharding算法执行)c.主节点选举。与quartz框架相比,调用API操作任务的方式不够人性化;需要将业务QuartzJobBean持久化到底层数据表中,系统侵入性较大。调度逻辑和QuartzJobBean耦合在同一个项目中,这会导致一个问题。当调度任务数量逐渐增多,调度任务逻辑逐渐增多时,调度系统的性能会受到业务的极大限制;Quartz关注点在于定时任务而不是数据,并没有一套基于数据处理的定制流程。Quartz虽然可以实现基于数据库的作业高可用,但是缺乏分布式并行调度的功能。综合对比总结和结论有共同点:E-Job和X-job都拥有广泛的用户基础和完备的技术文档,都能够满足定时任务的基本功能需求。不同点:X-Job侧重于简单的业务实现和方便的管理,简单的学习成本,丰富的失败策略和路由策略。推荐在“用户基数较小,服务器数量在一定范围内”的场景下使用。E-Job以数据为核心,加入了弹性扩展和数据分片的思想,最大限度地利用分布式服务器资源。但是学习成本比较高,建议在“数据量巨大,部署服务器数量多”的时候使用。
