分布式定时任务调度框架实践
分布式任务调度框架几乎是每个大型应用必备的工具,本文介绍了任务调度框架使用的需求背景和痛点,对业界普遍使用的开源分布式任务调度框架的使用进行了探究实践,并分析了这几种框架的优劣势和对自身业务的思考。
一、业务背景
1。1为什么需要使用定时任务调度
(1)时间驱动处理场景:整点发送优惠券,每天更新收益,每天刷新标签数据和人群数据。
(2)批量处理数据:按月批量统计报表数据,批量更新短信状态,实时性要求不高。
(3)异步执行解耦:活动状态刷新,异步执行离线查询,与内部逻辑解耦。
1。2使用需求和痛点
(1)任务执行监控告警能力。
(2)任务可灵活动态配置,无需重启。
(3)业务透明,低耦合,配置精简,开发方便。
(4)易测试。
(5)高可用,无单点故障。
(6)任务不可重复执行,防止逻辑异常。
(7)大任务的分发并行处理能力。
二、开源框架实践与探索
2。1Java原生Timer和
ScheduledExecutorService
2。1。1Timer使用
Timer缺陷:
Timer底层是使用单线程来处理多个Timer任务,这意味着所有任务实际上都是串行执行,前一个任务的延迟会影响到之后的任务的执行。
由于单线程的缘故,一旦某个定时任务在运行时,产生未处理的异常,那么不仅当前这个线程会停止,所有的定时任务都会停止。
Timer任务执行是依赖于系统绝对时间,系统时间变化会导致执行计划的变更。
由于上述缺陷,尽量不要使用Timer,idea中也会明确提示,使用ScheduledThreadPoolExecutor替代Timer。
2。1。2ScheduledExecutorService使用
ScheduledExecutorService对于Timer的缺陷进行了修补,首先ScheduledExecutorService内部实现是ScheduledThreadPool线程池,可以支持多个任务并发执行。
对于某一个线程执行的任务出现异常,也会处理,不会影响其他线程任务的执行,另外ScheduledExecutorService是基于时间间隔的延迟,执行不会由于系统时间的改变发生变化。
当然,ScheduledExecutorService也有自己的局限性:只能根据任务的延迟来进行调度,无法满足基于绝对时间和日历调度的需求。
2。2SpringTask
2。2。1SpringTask使用
springtask是spring自主开发的轻量级定时任务框架,不需要依赖其他额外的包,配置较为简单。
此处使用注解配置
2。2。2SpringTask缺陷
SpringTask本身不支持持久化,也没有推出官方的分布式集群模式,只能靠开发者在业务应用中自己手动扩展实现,无法满足可视化,易配置的需求。
2。3永远经典的Quartz
2。3。1基本介绍
Quartz框架是Java领域最著名的开源任务调度工具,也是目前事实上的定时任务标准,几乎全部的开源定时任务框架都是基于Quartz核心调度构建而成。
2。3。2原理解析
核心组件和架构
关键概念
(1)Scheduler:任务调度器,是执行任务调度的控制器。本质上是一个计划调度容器,注册了全部Trigger和对应的JobDetail,使用线程池作为任务运行的基础组件,提高任务执行效率。
(2)Trigger:触发器,用于定义任务调度的时间规则,告诉任务调度器什么时候触发任务,其中CronTrigger是基于cron表达式构建的功能强大的触发器。
(3)Calendar:日历特定时间点的集合。一个trigger可以包含多个Calendar,可用于排除或包含某些时间点。
(4)JobDetail:是一个可执行的工作,用来描述Job实现类及其它相关的静态信息,如Job的名称、监听器等相关信息。
(5)Job:任务执行接口,只有一个execute方法,用于执行真正的业务逻辑。
(6)JobStore:任务存储方式,主要有RAMJobStore和JDBCJobStore,RAMJobStore是存储在JVM的内存中,有丢失和数量受限的风险,JDBCJobStore是将任务信息持久化到数据库中,支持集群。
2。3。3实践说明
(1)关于Quartz的基本使用
可参考Quartz官方文档和网上博客实践教程。
(2)业务使用要满足动态修改和重启不丢失,一般需要使用数据库进行保存。
Quartz本身支持JDBCJobStore,但是其配置的数据表比较多,官方推荐配置可参照官方文档,超过10张表,业务使用比较重。
在使用的时候只需要存在基本trigger配置和对应任务以及相关执行日志的表即可满足绝大部分需求。
(3)组件化
将quartz动态任务配置信息持久化到数据库,将数据操作包装成基本jar包,供项目之间使用,引用项目只需要引入jar包依赖和配置对应的数据表,使用时就可以对Quartz配置透明。
(4)扩展集群模式
通过故障转移和负载均衡实现了任务的高可用性,通过数据库的锁机制来确保任务执行的唯一性,但是集群特性仅仅只是用来HA,节点数量的增加并不会提升单个任务的执行效率,不能实现水平扩展。Quartz插件
可以对特定需要进行扩展,比如增加触发器和任务执行日志,任务依赖串行处理场景,可参考:quartz插件实现任务之间的串行调度
2。3。4缺陷和不足
(1)需要把任务信息持久化到业务数据表,和业务有耦合。
(2)调度逻辑和执行逻辑并存于同一个项目中,在机器性能固定的情况下,业务和调度之间不可避免地会相互影响。
(3)quartz集群模式下,是通过数据库独占锁来唯一获取任务,任务执行并没有实现完善的负载均衡机制。
2。4轻量级神器XXLJOB
2。4。1基本介绍
XXLJOB是一个轻量级分布式任务调度平台,主打特点是平台化,易部署,开发迅速、学习简单、轻量级、易扩展,代码仍在持续更新中。
调度中心是任务调度控制台,平台自身并不承担业务逻辑,只是负责任务的统一管理和调度执行,并且提供任务管理平台,执行器负责接收调度中心的调度并执行,可直接部署执行器,也可以将执行器集成到现有业务项目中。通过将任务的调度控制和任务的执行解耦,业务使用只需要关注业务逻辑的开发。
主要提供了任务的动态配置管理、任务监控和统计报表以及调度日志几大功能模块,支持多种运行模式和路由策略,可基于对应执行器机器集群数量进行简单分片数据处理。
2。4。2原理解析
2。1。0版本前核心调度模块都是基于quartz框架,2。1。0版本开始自研调度组件,移除quartz依赖,使用时间轮调度。
2。4。3实践说明
详细配置和介绍参考官方文档。
2。4。3。1demo使用:
示例1:实现简单任务配置,只需要继承IJobHandler抽象类,并声明注解
JobHandler(valueofflineTaskJobHandler),实现业务逻辑即可。(注:此次引入了dubbo,后文介绍)。JobHandler(valueofflineTaskJobHandler)ComponentpublicclassOfflineTaskJobHandlerextendsIJobHandler{Reference(checkfalse,versioncmsdev,groupcmsservice)privateOfflineTaskExecutorFacadeofflineTaskExecutorFacade;OverridepublicReturnTStringexecute(Stringparam)throwsException{XxlJobLogger。log(offlineTaskJobHandlerstart。);try{offlineTaskExecutorFacade。executeOfflineTask;}catch(Exceptione){XxlJobLogger。log(offlineTaskJobHandlerexception。,e);returnFAIL;}XxlJobLogger。log(XXLJOB,offlineTaskJobHandlerend。);returnSUCCESS;}}
(滑动可查看)
示例2:分片广播任务。JobHandler(valueshardingJobHandler)ServicepublicclassShardingJobHandlerextendsIJobHandler{OverridepublicReturnTStringexecute(Stringparam)throwsException{分片参数ShardingUtil。ShardingVOshardingVOShardingUtil。getShardingVo;XxlJobLogger。log(分片参数:当前分片序号{},总分片数{},shardingVO。getIndex,shardingVO。getTotal);业务逻辑for(inti0;ishardingVO。getTotal;i){if(ishardingVO。getIndex){XxlJobLogger。log(第{}片,命中分片开始处理,i);}else{XxlJobLogger。log(第{}片,忽略,i);}}returnSUCCESS;}}
(滑动可查看)
2。4。3。2整合dubbo
(1)引入dubbospringbootstarter和业务facadejar包依赖。dependencygroupIdcom。alibaba。spring。bootgroupIddubbospringbootstarterartifactIdversion2。0。0versiondependencydependencygroupIdcom。demo。servicegroupIdxxxfacadeartifactIdversion1。9SNAPSHOTversiondependency
(滑动可查看)
(2)配置文件加入dubbo消费端配置(可根据环境定义多个配置文件,通过profile切换)。Dubbo服务消费者配置spring。dubbo。application。namexxljobspring。dubbo。registry。addresszookeeper:zookeeper。xyz:2183spring。dubbo。port20880spring。dubbo。versiondemospring。dubbo。groupdemoservice
(滑动可查看)
(3)代码中通过Reference注入facade接口即可。Reference(checkfalse,versiondemo,groupdemoservice)privateOfflineTaskExecutorFacadeofflineTaskExecutorFacade;
(滑动可查看)
(4)启动程序加入EnableDubboConfiguration注解。
SpringBootApplicationEnableDubboConfigurationpublicclassXxlJobExecutorApplication{publicstaticvoidmain(String〔〕args){SpringApplication。run(XxlJobExecutorApplication。class,args);}}
(滑动可查看)
2。4。4任务可视化配置
内置了平台项目,方便了开发者对任务的管理和执行日志的监控,并提供了一些便于测试的功能。
2。4。5扩展
(1)任务监控和报表的优化。
(2)任务报警方式的扩展,比如加入告警中心,提供内部消息,短信告警。
(3)对实际业务内部执行出现异常情况下的不同监控告警和重试策略。
2。5高可用ElasticJob
2。5。1基本介绍
ElasticJob是一个分布式调度解决方案,由两个相互独立的子项目ElasticJobLite和ElasticJobCloud组成。
ElasticJobLite定位为轻量级无中心化解决方案,使用jar包的形式提供分布式任务的协调服务。
ElasticJobCloud使用MesosDocker的解决方案,额外提供资源治理、应用分发以及进程隔离等服务。
可惜的是已经两年没有迭代更新记录。
2。5。2原理解析
2。5。3实践说明
2。5。3。1demo使用
(1)安装zookeeper,配置注册中心config,配置文件加入注册中心zk的配置。ConfigurationConditionalOnExpression({regCenter。serverList}。length0)publicclassJobRegistryCenterConfig{Bean(initMethodinit)publicZookeeperRegistryCenterregCenter(Value({regCenter。serverList})finalStringserverList,Value({regCenter。namespace})finalStringnamespace){returnnewZookeeperRegistryCenter(newZookeeperConfiguration(serverList,namespace));}}
(滑动可查看)spring。application。namedemoelasticjobregCenter。serverListlocalhost:2181regCenter。namespacedemoelasticjobspring。datasource。urljdbc:mysql:127。0。0。1:3306xxljob?UnicodetruecharacterEncodingUTF8spring。datasource。usernameuserspring。datasource。passwordpwd
(滑动可查看)
(2)配置数据源config,并配置文件中加入数据源配置。GetterSetterNoArgsConstructorAllArgsConstructorToStringConfigurationConfigurationProperties(prefixspring。datasource)publicclassDataSourceProperties{privateStringurl;privateStringusername;privateStringpassword;BeanPrimarypublicDataSourcegetDataSource{DruidDataSourcedataSourcenewDruidDataSource;dataSource。setUrl(url);dataSource。setUsername(username);dataSource。setPassword(password);returndataSource;}}
(滑动可查看)spring。datasource。urljdbc:mysql:127。0。0。1:3306xxljob?UnicodetruecharacterEncodingUTF8spring。datasource。usernameuserspring。datasource。passwordpwd
(滑动可查看)
(3)配置事件config。ConfigurationpublicclassJobEventConfig{AutowiredprivateDataSourcedataSource;BeanpublicJobEventConfigurationjobEventConfiguration{returnnewJobEventRdbConfiguration(dataSource);}}
(滑动可查看)
(4)为了便于灵活配置不同的任务触发事件,加入ElasticSimpleJob注解。Target({ElementType。TYPE})Retention(RetentionPolicy。RUNTIME)publicinterfaceElasticSimpleJob{AliasFor(cron)Stringvaluedefault;AliasFor(value)Stringcrondefault;StringjobNamedefault;intshardingTotalCountdefault1;StringshardingItemParametersdefault;StringjobParameterdefault;}
(滑动可查看)
(5)对配置进行初始化。ConfigurationConditionalOnExpression({elaticjob。zookeeper。serverlists}。length0)publicclassElasticJobAutoConfiguration{Value({regCenter。serverList})privateStringserverList;Value({regCenter。namespace})privateStringnamespace;AutowiredprivateApplicationContextapplicationContext;AutowiredprivateDataSourcedataSource;PostConstructpublicvoidinitElasticJob{ZookeeperRegistryCenterregCenternewZookeeperRegistryCenter(newZookeeperConfiguration(serverList,namespace));regCenter。init;MapString,SimpleJobmapapplicationContext。getBeansOfType(SimpleJob。class);for(Map。EntryString,SimpleJobentry:map。entrySet){SimpleJobsimpleJobentry。getValue;ElasticSimpleJobelasticSimpleJobAnnotationsimpleJob。getClass。getAnnotation(ElasticSimpleJob。class);StringcronStringUtils。defaultIfBlank(elasticSimpleJobAnnotation。cron,elasticSimpleJobAnnotation。value);SimpleJobConfigurationsimpleJobConfigurationnewSimpleJobConfiguration(JobCoreConfiguration。newBuilder(simpleJob。getClass。getName,cron,elasticSimpleJobAnnotation。shardingTotalCount)。shardingItemParameters(elasticSimpleJobAnnotation。shardingItemParameters)。build,simpleJob。getClass。getCanonicalName);LiteJobConfigurationliteJobConfigurationLiteJobConfiguration。newBuilder(simpleJobConfiguration)。overwrite(true)。build;JobEventRdbConfigurationjobEventRdbConfigurationnewJobEventRdbConfiguration(dataSource);SpringJobSchedulerjobSchedulernewSpringJobScheduler(simpleJob,regCenter,liteJobConfiguration,jobEventRdbConfiguration);jobScheduler。init;}}}
(滑动可查看)
(6)实现SimpleJob接口,按上文中方法整合dubbo,完成业务逻辑。ElasticSimpleJob(cron10?,jobNameOfflineTaskJob,shardingTotalCount2,jobParameter测试参数,shardingItemParameters0A,1B)ComponentpublicclassMySimpleJobimplementsSimpleJob{LoggerloggerLoggerFactory。getLogger(OfflineTaskJob。class);Reference(checkfalse,versioncmsdev,groupcmsservice)privateOfflineTaskExecutorFacadeofflineTaskExecutorFacade;Overridepublicvoidexecute(ShardingContextshardingContext){offlineTaskExecutorFacade。executeOfflineTask;logger。info(String。format(ThreadID:s,作业分片总数:s,当前分片项:s。当前参数:s,作业名称:s。作业自定义参数:s,Thread。currentThread。getId,shardingContext。getShardingTotalCount,shardingContext。getShardingItem,shardingContext。getShardingParameter,shardingContext。getJobName,shardingContext。getJobParameter));}}
(滑动可查看)
2。6其余开源框架
(1)Saturn:Saturn是唯品会开源的一个分布式任务调度平台,在ElasticJob的基础上进行了改造。
(2)SIATASK:是宜信开源的分布式任务调度平台。
三、优劣势对比和业务场景适配思考
业务思考:
丰富任务监控数据和告警策略。
接入统一登录和权限控制。
进一步简化业务接入步骤。
四、结语
对于并发场景不是特别高的系统来说,xxljob配置部署简单易用,不需要引入多余的组件,同时提供了可视化的控制台,使用起来非常友好,是一个比较好的选择。希望直接利用开源分布式框架能力的系统,建议根据自身的情况来进行合适的选型。
附:参考文献
quartz插件实现任务之间的串行调度
链路追踪(Tracing)的前世今生(上)
基于GraphQL平台化BFF构建及微服务治理
石墨文档Websocket百万长连接技术实践
DBCP数据库连接打满原因分析
Serverless:微服务架构的终极模式
技术原创及架构实践文章,欢迎通过公众号菜单联系我们进行投稿。
高可用架构
改变互联网的构建方式
警惕!你每天都在做的这件事,正在威胁健康炒菜是家家户户每日都要做的事情但不恰当的烹饪方式也会对身体产生很多伤害比如致癌、伤心脏、毁大脑等等如何选择正确的烹饪方式?如何选择合适的食用油?……
惨遭逆转!浓眉3712,塔图姆449,詹姆斯太无奈,威少成遮北京时间12月14日,NBA常规赛湖人主场迎战凯尔特人,赛前,湖人11胜15负排名西部第12,而绿军21胜7负位居东部榜首,两队战绩差距明显,但绿军是背靠背作战,且之前连负勇士……
天赋是何物头条作者云开日初真正努力过的人,才知道天赋有多重要。头条作者云开日初每个人的天赋确实不同,就像有些人天生长得帅,长得美貌,这真是没有办法的事情!人从生下……
解决方案火力发电行业中七腾智能巡检机器人的应用火力发电指的是利用煤、石油和天然气等固体、液体、气体燃料燃烧时产生的热能,通过发电装置转换成电能的一种发电方式。在新能源成为新型电力系统的主体电源之前,以煤为主的火电,一直都是……
头皮痒的人认真看如有这一些情况出现,证明它已失控螨虫头的人认真看:如有这一些情况出现,证明螨虫已失控头发轻盈、柔顺、乌黑、浓密的秀发轻轻一甩,发丝轻舞飞扬,足以迷倒众生。但现实是:一甩头发,却甩出了邋遢的头屑;;……
漪字取名寓意及含义冬日生活打卡季漪字拼音是y,寓意着光鲜亮丽、引人注目、神采飞扬、美丽、吉祥等。其字本身的含义是水波纹,风吹水面形成的波纹,也指岸边。用作人名意指美丽、吉祥、小巧的含义;也……
高原重升烟火气来源:经济日报周末,记者走进位于西藏拉萨市城关区的万达广场三楼,空气中弥漫着各种食物的香味儿;万达影城售票大厅滚动播放着《阿凡达2》的场次,前来观影的人正有序进入;各种服……
卡拉彼丘实机PV首曝,首个二次元真射击游戏登场二次元第三人称射击游戏《卡拉彼丘》于今日(12月24日)曝光首个实机PV,并于即日起开放首次PC测试招募。游戏由Day1工作室自主开发,并计划在PC、移动端多端上线。硬核……
全球规模最大叔碳新材料一体化项目在沧州开工建设冀时客户端报道(河北台任亚栋李德财许丙路通讯员祖天林李其征)记者从沧州临港经济技术开发区宣传部门获悉,日前,河北四友叔碳新材料有限公司投资11。2亿元,年产74。5万吨叔碳新材……
供销社概念全面解析刚刚开完的大会中已经明确了方针,乡村振兴战略乃是高质量发展的压舱石,我们必须要全面推进乡村振兴,坚持农业农村优先发展,加快建设农业强国。逻辑:最近几天,湖北日报一则恢复重……
时间定了!油价又要变来源:新晚报第21轮国内成品油零售价将于11月7日(下周一)开启目前预测本轮油价调整或要上涨了!国内油价第21轮调整,将于11月7日24时开启,前……
OPPO新机配置曝光代号赫本,120Hz曲屏108MP主摄IT之家11月3日消息,今日,数码博主数码闲聊站曝光了一款代号为赫本的OPPO新机。该博主透露,这款OPPO新机采用6。7英寸居中单孔曲屏,拥有24121080P分辨率与……