在日常开发中 我们经常会碰到需要设计一个定时任务去批量处理某个业务的情况
例如蚂蚁森林每天早上要把上一天的步数转换为能量供大家收取
基金公司每天早上会计算投资人的收益
在单机环境下 我们开发一个定时任务 用JDK的timer类 或者
Collection包下的ScheduledExecutorService就可以
但是应用一旦分布式部署,那每个节点的机器都会执行相同的定时任务 显然这不是我们愿意看到的
所以在分布式环境下,我们需要一套任务调度系统 将我们的任务去集中化的管理 统一调度
那么设计一款这样的分布式任务调度系统 需要考虑到哪些关键点呢
首先我们需要一个管理控制台进行任务的发布,这个控制台可以是PC端的页面也可以是一个移动端的APP
然后有一个任务管理系统对任务进行管理和调度,等到了设置好的时间点,就把执行的指令下发到对应的应用上
首先我们看任务发布,在这个发布页,我们需要制定任务执行的路径,也就是具体哪个类来执行任务,我们把这个
类称作为任务单元,一般这个任务单元会实现某个公共的接口,例如叫JobProcessor之类的,同时我们要配置是
哪台机器来执行这个任务,这个机器部署在什么环境下,是预发还是生产还是日常,我们把这台机器上的应用
称为执行器,一个执行器就是一个应用,应用里面有多个任务单元,如果不指定具体的机器的话,我们可以设置为
随机选择一台当前在线的执行器去执行,另外我们要设置这个任务是什么时候执行,例如每天早上1点的01分01秒
那么到底什么是任务发布呢,其实就是任务的新增和修改,如果你觉得每次新增任务都需要到管理控制台操作下发布流程太麻烦
那么我们可以去扫描某个接口或者注解 将这些任务单元扫描出来 主动上报到任务管理中心 这样每次执行器启动的时候
都会进行上报的动作,任务管理中心收到这些请求,会进行任务单元的去重,因为多个执行器上报的任务单元可能是一样的
当然任务的调度时间 调度策略 是否重试 执行失败是否通知相关负责人 邮件 电话 短信 这些也可以作为注解的一个参数进行上报
有了任务我们就要考虑怎么调度这些任务了,比如我设置了每天早上1点01分01秒执行某个任务,那么到了这个时间点该如何调度对应的任务呢
首先从操作系统层面上来看,就是设置PIT定时器的初始值,每次时钟滴答一下,这个值就减1,等减到0的时候,就会发出一个中断,
然后执行某个回调方法,在这个回调方法里面进行注册的任务
具体到jdk上面就是Timer类和ScheduledExecutorService,但是要实现Cron表达式的时间配置,最好借用Quartz这个工具
那么这个调度器怎么把调度指令发给对应的执行器去执行呢首先我们想到的肯定是RPC框架,但是目前流行的RPC框架都比较重
执行器需要加很多的依赖有可能和执行器本身的RPC框架有冲突,在这种情况下我们可以借助Netty来实现一个简单的RPC框架
只要能够接收命令就可以,当然我们也可以在执行器上监听某个http端口,调度器只需要借助HTTPclient发送Http请求就可以
如果调度器本身就是一个web服务的话,我们可以增加一个公共的Servlet,然后再这个Servlet里面解析请求指令,最后再调用到
具体的任务单元里
例如Servlet接收到这个请求后,解析这个指令是测试还是执行任务 还是终止任务 分别对应不同的处理逻辑
现在任务指令已经可以发送到执行器了 那么现在分布式环境下我们具体选择哪台执行器进行执行呢
首先他必须是在线的,所以调度器最好能维护所以执行器的状态 也就是我们经常说的探活机制
探活的实现我们可以基于NIO来实现,我们也可以借助Zookeeper,当然企业内部如果已经维护了应用的状态
,这个算法可以随机或者顺序执行 只要不把所有的请求都打到同一个执行器就行
有些公司会把任务直接写在Service服务里面,这样任务执行就可以少一次RPC执行
有些公司会把任务单独抽出来一个应用单独进行部署 如果RPC调用Service层,这样就能避免执行任务时的资源消耗影响到Service层
本身的服务
到这里一个分布式任务调度系统的雏形就已经形成了 我们简单总结一下 一个分布式任务调度系统里面需要有调度器,调度器需要下发指令给
执行器吗,调度器可以根据路由算法选择把任务指令下发给哪台机器,调度器需要设计定时任务什么时候去触发
接下来我们再挖掘几个特殊的需求
一个是任务的分片,当然我们有一个很大的批量任务要执行的时候,这肯定不会是一个单机在跑,跨机房跨地区不同维度的进行分片
然后分散给多个执行器同时执行,那么任务调度系统能否以中间件的形式提供一个分片的策略自动进行分片
例如根据某个字段的哈希值求余,然后分配到不同的执行器,或者根据时间的维度进行拆分 具体的实现可以参考数据库的分库分表的设计
另外一个特殊的需求是,我们有时候会遇到这样一种情况,需要紧急对线上的数据做批量的订正,又不想重新发布,那我能不能直接写段脚本
推送到执行器上执行 也就是GLUE模式,这个需求我们可以借助groovy来实现
分布式任务调度系统
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 分布式调度在互联网企业中占据着十分重要的作用,尤其是电子商务领域,由于存在数据量大、高并发的特点,对数据处理的要求...