当前位置: 首页 > 科技观察

架构师如何选择分布式定时任务?

时间:2023-03-21 22:41:28 科技观察

当我们的业务服务需要定时执行业务接口时,就需要考虑引入定时任务。那么问题又来了。我们选择“分布式定时任务”吗?或“本地工作”。那么,这里我就带大家从技术和架构的角度来看这个问题。线程和线程池熟悉线程和线程池的应该都知道,使用它们可以实现定时功能。RocketMQ中比较常见的定时任务的编写方式是使用线程来实现定时任务,即Thread类。简单点说就是线程等待。下面代码的语义是按照固定的周期waitInterval进行负载均衡。@Overridepublicvoidrun(){log.info(this.getServiceName()+"服务启动");while(!this.isStopped()){this.waitForRunning(waitInterval);this.mqClientFactory.doRebalance();}log.info(this.getServiceName()+"serviceend");}RocketMQ还有一种比较常见的定时任务的写法,就是使用线程池来实现定时任务,就是ScheduledExecutorService类。下面代码的语义是周期性注册BrokerServer。this.scheduledExecutorService.scheduleAtFixedRate(newRunnable(){@Overridepublicvoidrun(){try{BrokerController.this.registerBrokerAll(true,false,brokerConfig.isForceRegister());}catch(Throwablee){log.error("registerBrokerAllException",e);}}},1000*10,Math.max(10000,Math.min(brokerConfig.getRegisterNameServerPeriod(),60000)),TimeUnit.MILLISECONDS);那么既然RocketMQ可以利用线程和池来完成定时任务,那么我们的业务服务也是可以的。JDK自带的定时器Timer和TimerTask本质上都是线程实现的定时功能,所以RocketMQ直接使用线程和线程池来实现个性化的定时任务。人们这样做并不是没有道理的。比如RocketMQ中的延时消息就是使用TimerTask实现的。当然,使用定时器Timer和TimerTask会有很多缺陷,比如没有分布式调度功能,不能保证在分布式环境下执行Job的数据一致性。然而,RocketMQ没有必要考虑这样的场景。它的分布式问题通过其他替代方法解决,例如集群选举。SpringFramework自带的定时器熟悉SpringFramework框架的应该都知道,可以使用注解@EnableScheduling和@Scheduled来启动一个定时任务。我们可以这样写一个定时器。@Component@EnableSchedulingpublicclassSimulatingMultithreadedOrder{@Scheduled(fixedRate=2000)publicvoidproducerMessage()throwsMQClientException{//定时执行的逻辑}}使用SpringFramework框架自带的本地定时任务非常方便。如果你的基础框架使用了SpringBoot或者更高级的SpringCloudAlibaba,你不需要额外添加Jar包依赖,因为@EnableScheduling和@Scheduled是SpringContext提供给我们的定时任务注解,只要你是Spring框架生态业务服务,使用起来非常简单。QuartzQuartz可以说是一个非常古老的定时任务框架。最新版本是2.3.2。该项目最后一次更新是在2019年,也就是说它处于暂停状态,但这并不影响它的关注度。毕竟是规范的。看过Quartz底层源码的技术人员应该都知道,Quartz使用了大量的线程来实现定时任务的功能,比如执行任务的线程池和调度任务的线程池。xxl-job的作者多年前就接触过xxl-job,也是看着它成长起来的。这个框架的作者也很厉害,这个框架一直由我维护到现在。如果我没记错的话,应该快10年了。在Github上搜索xxl-job,目前Forks数8.9k,Star数20.9k,这个成绩已经超过了很多Apache顶级项目的数据,其最新版本是v2.3.0,社区活跃度还是很高的。xxl-job将自己定位为一个分布式任务调度平台,也就是说它不仅做定时任务,还做调度,这与云原生的概念不谋而合。xxl-job的原理可以参考官方https://github.com/xuxueli/xxl-job。分布式作业的原理其实并不难。多练习,看源码就大致知道它是如何完成调度的。笔者也下载了它的源码,看了一下。其实它本质上是一个线程实现的定时作业,只是加入了一些动态的调度规则,可以非常优雅动态的kill和runjob。thread,完成线程Job的调度。作者一开始关注xxl-job,主要是那个版本去掉了ZooKeeper,写了一套分布式一致性框架。大概忘了是在哪个版本改进的。Elastic-jobElastic-job是Apache的顶级项目。它已重命名为shardingsphere-elasticjob。具体数据如下。shardingsphere-elasticjob和xxl-job最大的区别是前者仍然严重依赖ZooKeeper。毕竟ZooKeeper也是一个Apache项目。哈哈,肯定不会删的。还有一个比较大的区别就是shardingsphere-elasticjob的定时任务规范是依赖Quartz二次开发的产品,而xxl-job完全是自己写的。目前shardingsphere-elasticjob最新版本为3.0.1,社区活跃度很高。如果对源码感兴趣,可以下载相关源码,https://github.com/apache/shardingsphere-elasticjob。shardingsphere-elasticjob由两部分组成:Elastic-Job-Lite定位为轻量级去中心化解决方案,以jar包的形式为分布式任务提供协调服务;Elastic-Job-Cloud使用Mesos+Docker(TBD)解决方案提供资源管理、应用程序分发和进程隔离等附加服务。SaturnSaturn是唯品会在github上开源的一款分布式任务调度产品。基于当当网elastic-job1.0版本开发,改进了部分功能,增加了一些新特性。Saturn最新版本是v3.5.1,社区活跃度不是很高。antaresAntares是一款自主研发的个人维护定时任务框架。Antares目前最新版本是1.4.0,最后一次更新是2017年,几乎处于停维护状态。SpringCloudAlibabaCloudSchedulerXSchedulerX(分布式任务调度)是阿里云EDAS产品的一个组件。SpringCloudAliCloudSchedulerX为SpringCloud配置规范下的分布式任务调度提供功能支持。SchedulerX可以提供秒级、精准、高可靠、高可用的定时任务调度服务,支持简单单机任务、简单多机任务、脚本任务、网格任务等多种类型的任务调度。阿里巴巴没有开放SpringCloudAlibabaCloudSchedulerX的源码,这是一个漏洞,我们只能使用阿里云的商业版。总之,无论是哪种分布式定时作业,都会有其适用的业务场景。没有人是绝对好或绝对坏的。就像RPC框架一样,最重要的是适合。一个优秀框架的架构和设计思想是非常有用的。让我们学会它,为自己所用,也是一种能力的提升。毕竟,我们必须先学会模仿,然后才能学会创新。