分布式定时任务开源框架
- Elastic-Job(当当网)
- light-task-scheduler
- clover
- TBSchedule(阿里)
- niubi-job
- Uncode-Schedule
分布式定时任务开源框架
单机定式任务调度的问题 在很多应用系统中我们常常要定时执行一些任务。比如,订单系统的超时状态判断、缓存数据的定时更新、定式给用户发邮件,甚至是一些定期计算的报表等等。常见的处理方式有线程的while(true) 和sleep组合、使用Timer定时器触发任务又或者是使用quartz框架。貌似这些方法可以完美的解决方案,为什么还需要分布式呢?主要有如下两点原因:
1.高可用:单机版的定式任务调度只能在一台机器上运行,如果程序或者系统出现异常就会导致功能不可用。虽然可以在单机程序实现的足够稳定,但始终有机会遇到非程序引起的故障,而这个对于一个系统的核心功能来说是不可接受的。
2.单机处理极限:原本1分钟内需要处理1万个订单,但是现在需要1分钟内处理10万个订单;原来一个统计需要1小时,现在业务方需要10分钟就统计出来。你也许会说,你也可以多线程、单机多进程处理。的确,多线程并行处理可以提高单位时间的处理效率,但是单机能力毕竟有限(主要是CPU、内存和磁盘),始终会有单机处理不过来的情况。
这个时候就需要分布式的定时任务来实现了。业内常用的分布式定式任务解决方案主要有quartz、淘宝的TBSchedule和当当的elastic-job。
quartz的单机版本大家应该比较熟悉,它的集群方案是使用数据库来实现的。 上图三个节点在数据库中都拥有同一份Job定义,如果某一个节点失效,那么Job会在其他节点上执行。由于三个节点上的Job执行代码是一样的,那么怎么保证只有在一台机器上触发呢?答案是使用了数据库锁。在quartz的集群解决方案里有张表scheduler_locks,quartz采用了悲观锁的方式对triggers表进行行加锁,以保证任务同步的正确性。一旦某一个节点上面的线程获取了该锁,那么这个Job就会在这台机器上被执行,同时这个锁就会被这台机器占用。同时另外一台机器也会想要触发这个任务,但是锁已经被占用了,就只能等待,直到这个锁被释放。之后会看trigger状态,如果已经被执行了,则不会执行了。
简单地说,quartz的分布式调度策略是以数据库为边界资源的一种异步策略。各个调度器都遵守一个基于数据库锁的操作规则从而保证了操作的唯一性。同时多个节点的异步运行保证了服务的可靠。但这种策略有自己的局限性:集群特性对于高CPU使用率的任务效果很好,但是对于大量的短任务,各个节点都会抢占数据库锁,这样就出现大量的线程等待资源。这种情况随着节点的增加会越来越严重。
另外,quartz的分布式只是解决了高可用的问题,并没有解决任务分片的问题,还是会有单机处理的极限。
TBSchedule是一款非常优秀的高性能分布式调度框架,广泛应用于阿里巴巴、淘宝、支付宝、京东、聚美、汽车之家、国美等很多互联网企业的流程调度系统。tbschedule在时间调度方面虽然没有quartz强大,但是它支持分片功能。和quartz不同的是,tbschedule使用ZooKeeper来实现任务调度的高可用和分片。
TBSchedule的分布式机制是通过灵活的Sharding方式实现的,分片的规则由客户端决定,比如可以按所有数据的ID按10取模分片、按月份分片等等。TBSchedule的宿主服务器可以进行动态扩容和资源回收,这个特点主要是因为它后端依赖的ZooKeeper,这里的ZooKeeper对于TBSchedule来说是一个NoSQL,用于存储策略、任务、心跳信息数据,它的数据结构类似文件系统的目录结构,它的节点有临时节点、持久节点之分。调度引擎启动后,随着业务量数据量的增多,当前Cluster可能不能满足目前的处理需求,那么就需要增加服务器数量,一个新的服务器上线后会在ZooKeeper中创建一个代表当前服务器的一个唯一性路径(临时节点),并且新上线的服务器会和ZooKeeper保持长连接,当通信断开后,节点会自动摘除。
TBSchedule会定时扫描当前服务器的数量,重新进行任务分配。TBSchedule不仅提供了服务端的高性能调度服务,还提供了一个scheduleConsole的war包,随着宿主应用的部署直接部署到服务器,可以通过web的方式对调度的任务、策略进行监控管理,以及实时更新调整。
Elastic-Job当当开源的分布式调度解决方案,由两个相互独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成。Elastic-Job-Lite定位为轻量级无中心化解决方案,使用jar包的形式提供分布式任务的协调服务。一般我们只要使用Elastic-Job-Lite就好。
Elastic-Job-Lite并没有宿主程序,而是基于部署作业框架的程序在到达相应时间点时各自触发调度。它的开发也比较简单,引用Jar包实现一些方法即可,最后编译成Jar包运行。Elastic-Job-Lite的分布式部署全靠ZooKeeper来同步状态和原数据。实现高可用的任务只需将分片总数设置为1,并把开发的Jar包部署于多个服务器上执行,任务将会以1主N从的方式执行。一旦本次执行任务的服务器崩溃,其他执行任务的服务器将会在下次作业启动时选择一个替补执行。如果开启了失效转移,那么功能效果更好,可以保证在本次作业执行时崩溃,备机之一立即启动替补执行。
Elastic-Job-Lite的任务分片也是通过ZooKeeper来实现,Elastic-Job并不直接提供数据处理的功能,框架只会将分片项分配至各个运行中的作业服务器,开发者需要自行处理分片项与真实数据的对应关系。框架也预置了一些分片策略:平均分配算法策略,作业名哈希值奇偶数算法策略,轮转分片策略。同时也提供了自定义分片策略的接口。
另外Elastic-Job-Lite还提供了一个任务监控和管理界面:Elastic-Job-Lite-Console。它和Elastic-Job-Lite是两个完全不关联的应用程序,使用ZooKeeper来交换数据,管理人员可以通过这个界面查看、监控和管理Elastic-Job-Lite的任务,必要的时候还能手动触发任务。
elastic-job结合了quartz非常优秀的时间调度功能,并且利用ZooKeeper实现了灵活的分片策略。除此之外,还加入了大量实用的监控和管理功能,以及其开源社区活跃、文档齐全、代码优雅等优点,是分布式任务调度框架的推荐选择。
Saturn是唯品会在github开源的一款分布式任务调度产品。它是基于当当elastic-job来开发的,其上完善了一些功能和添加了一些新的feature。目前在github上开源大半年,470个star。Saturn的任务可以用多种语言开发比如python、Go、Shell、Java、Php。其在唯品会内部已经发部署350+个节点,每天任务调度4000多万次。同时,管理和统计也是它的亮点。
分布式调度在互联网企业中占据着十分重要的作用,尤其是电子商务领域,由于存在数据量大、高并发的特点,对数据处理的要求较高,既要保证高效性,也要保证准确性和安全性,相对比较耗时的业务逻辑往往会从中剥离开来进行异步处理。
接下来,推荐几款优秀和极具潜力的国产开源分布式任务调度系统,希望能对大家有所帮助。
1、opencron opencron 是一个功能完善且通用的开源定时任务调度系统,拥有先进可靠的自动化任务管理调度功能,提供可操作的 web 图形化管理满足多种场景下各种复杂的定时任务调度,同时集成了 linux 实时监控、webssh 等功能特性。
2、LTS
LTS,light-task-scheduler,是一款分布式任务调度框架, 支持实时任务、定时任务和 Cron 任务。有较好的伸缩性和扩展性,提供对 Spring 的支持(包括 Xml 和注解),提供业务日志记录器。支持节点监控、任务执行监、JVM 监控,支持动态提交、更改、停止任务。
3、XXL-JOB XXL-JOB 是一个轻量级分布式任务调度框架,支持通过 Web 页面对任务进行 CRUD 操作,支持动态修改任务状态、暂停/恢复任务,以及终止运行中任务,支持在线配置调度任务入参和在线查看调度结果。
4、Elastic-Job Elastic-Job 是一个分布式调度解决方案,由两个相互独立的子项目 Elastic-Job-Lite 和 Elastic-Job-Cloud 组成。定位为轻量级无中心化解决方案,使用 jar 包的形式提供分布式任务的协调服务。支持分布式调度协调、弹性扩容缩容、失效转移、错过执行作业重触发、并行调度、自诊断和修复等等功能特性。
5、Uncode-Schedule
Uncode-Schedule 是基于 ZooKeeper + Quartz / spring task 的分布式任务调度组件,确保每个任务在集群中不同节点上不重复的执行。支持动态添加和删除任务,支持添加 ip 黑名单,过滤不需要执行任务的节点。
6、Antares
Antares 是一款基于 Quartz 机制的分布式任务调度管理平台,内部重写执行逻辑,一个任务仅会被服务器集群中的某个节点调度。用户可通过对任务预分片,有效提升任务执行效率;也可通过控制台 antares-tower 对任务进行基本操作,如触发,暂停,监控等。
分布式定时任务框架---Uncode Schedule
作为一个支付公司的项目组,经常会有很多对账功能(签约对账、支付订单对账、记账对账),这些都是以定时任务的形式实现,组内经常需要维护一些定时任务,在使用过程中主要关注定时任务的稳定性、健壮性和可控性,分布式定时任务+任务监控基本满足使用需求。
定时任务的现状 就定时任务来说,首先是操作系统层面一直支持的功能,所以我们的各种对定时任务的实现手段才能得以发挥。由于操作系统和编程语言种类繁多,本文中将重点从linux操作系统、java语言以及java生态中开源框架来介绍定时任务。
这是一个系统级的定时器,具有灵活简单的特性,同时也是缺乏管理功能和分布式支持。一般的使用方法是,使用shell脚本调用业务实现jar包。
这是一个java语言内置的定时器,这是所有基于java语言的开源框架实现的基础。其中,典型的任务调度方法:
public void schedule(TimerTask task, long delay); public void schedule(TimerTask task, Date time); public void schedule(TimerTask task, long delay, long period); public void schedule(TimerTask task, Date firstTime, long period); public void scheduleAtFixedRate(TimerTask task, long delay, long period); public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period);
3.1. Quartz(java定时任务的标准) 3.2. spring task 在spring中实现定时任务有两种方式,一是spring对quartz进行了封装,二是独立实现了定时任务的调度器称为spring task。其中spring task相对较为简单,cron表达式不支持L W;而quartz不但完整支持cron表达式,而且具有很多高级特性,如JDBCJobStore(作业仓库)、集群模式。
根据我们所有定时任务的特点和实际运行需求,我选择了Uncode-Schedule框架,这个框架相对简单、灵活,并且修改源代码以满足特定需求相对容易。
分布式定时任务面临的问题 对于分布式应用来说,一致性始终是首要问题,另外就是对任务和执行任务的机器的管理问题。
1.4. 心跳检测
任务的管理和监控
2.1. 任务的动态添加和删除
2.2. 控制执行任务的机器
2.3. 随时手动执行任务
Uncode-Schedule开源框架分析 Uncode-Schedule是一个实现分布式定时任务的开源框架,java语言实现,本章将从上面的几个问题入手分析该框架的实现机制。
2.4. 手动执行任务时,需要选择在哪台机器执行。
模块架构
3.1. Uncode-Schedule分布式定时任务的设计结构如下图:
zookeeper集群负责存储定时任务和机器的数据,起到存储数据和保持一致性的关键作用。在所有的执行任务的节点中有一个leader,它会负责任务的分配。任务的管理和监控平台可单独部署。 3.2. 每一个任务节点的内部结构如下图:
执行任务的节点上支持的任务类型包括spring的封装的quartz任务和spring task;另外该框架还自定义了一种任务Uncode Task,实际上是一种由zookeeper存储调度信息的任务,最终还是由spring的调度器ThreadPoolTaskScheduler控制的,不过这种任务是可动态添加和删除的。
我根据对框架的功能完善,自己设计了一个任务的管理和监控平台。主要在其中添加了手动执行的功能,其他的监控功能会进一步完善。
作者:rabbitGYK 链接:https://www.jianshu.com/p/780235132d81