在不少应用系统中咱们经常要定时执行一些任务。好比,订单系统的超时状态判断、缓存数据的定时更新、定式给用户发邮件,甚至是一些按期计算的报表等等。常见的处理方式有线程的while(true) 和sleep组合、使用Timer定时器触发任务又或者是使用quartz框架。貌似这些方法能够完美的解决方案,为何还须要分布式呢?主要有以下两点缘由:python
1.高可用:单机版的定式任务调度只能在一台机器上运行,若是程序或者系统出现异常就会致使功能不可用。虽然能够在单机程序实现的足够稳定,但始终有机会遇到非程序引发的故障,而这个对于一个系统的核心功能来讲是不可接受的。git
2.单机处理极限:本来1分钟内须要处理1万个订单,可是如今须要1分钟内处理10万个订单;原来一个统计须要1小时,如今业务方须要10分钟就统计出来。你也许会说,你也能够多线程、单机多进程处理。的确,多线程并行处理能够提升单位时间的处理效率,可是单机能力毕竟有限(主要是CPU、内存和磁盘),始终会有单机处理不过来的状况。github
这个时候就须要分布式的定时任务来实现了。业内经常使用的分布式定式任务解决方案主要有quartz、淘宝的TBSchedule和当当的elastic-job。web
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多万次。同时,管理和统计也是它的亮点。
有兴趣的同窗能够从https://github.com/vipshop/Saturn 上了解更加详细的信息。