任务调度系统就该这么设计(万能通用),稳的一批! 下

简介: 任务调度系统就该这么设计(万能通用),稳的一批! 下

4 中心化流派

中心化的原理是:把调度和任务执行,隔离成两个部分:调度中心和执行器。调度中心模块只需要负责任务调度属性,触发调度命令。执行器接收调度命令,去执行具体的业务逻辑,而且两者都可以进行分布式扩容。

4.1 MQ模式

先谈谈我在艺龙促销团队接触的第一种中心化架构。

调度中心依赖Quartz集群模式,当任务调度时候,发送消息到RabbitMQ 。业务应用收到任务消息后,消费任务信息。

这种模型充分利用了MQ解耦的特性,调度中心发送任务,应用方作为执行器的角色,接收任务并执行。

但这种设计强依赖消息队列,可扩展性和功能,系统负载都和消息队列有极大的关联。这种架构设计需要架构师对消息队列非常熟悉。

4.2 XXL-JOB

XXL-JOB 是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。

xxl-job 2.3.0架构图

我们重点剖析下架构图 :

▍ 网络通讯 server-worker 模型

调度中心和执行器 两个模块之间通讯是 server-worker 模式。调度中心本身就是一个SpringBoot 工程,启动会监听8080端口。

执行器启动后,会启动内置服务( EmbedServer )监听9994端口。这样双方都可以给对方发送命令。

那调度中心如何知道执行器的地址信息呢 ?上图中,执行器会定时发送注册命令 ,这样调度中心就可以获取在线的执行器列表。

通过执行器列表,就可以根据任务配置的路由策略选择节点执行任务。常见的路由策略有如下三种:

  • 随机节点执行:选择集群中一个可用的执行节点执行调度任务。适用场景:离线订单结算。

  • 广播执行:在集群中所有的执行节点分发调度任务并执行。适用场景:批量更新应用本地缓存。
  • 分片执行:按照用户自定义分片逻辑进行拆分,分发到集群中不同节点并行执行,提升资源利用效率。适用场景:海量日志统计。

▍ 调度器

调度器是任务调度系统里面非常核心的组件。XXL-JOB 的早期版本是依赖Quartz。

但在v2.1.0版本中完全去掉了Quartz的依赖,原来需要创建的 Quartz表也替换成了自研的表。

核心的调度类是:JobTriggerPoolHelper 。调用start方法后,会启动两个线程:scheduleThread 和 ringThread 。

首先 scheduleThread 会定时从数据库加载需要调度的任务,这里从本质上还是基于数据库行锁保证同时只有一个调度中心节点触发任务调度。

Connection conn = XxlJobAdminConfig.getAdminConfig()
                  .getDataSource().getConnection();
connAutoCommit = conn.getAutoCommit();
conn.setAutoCommit(false);
preparedStatement = conn.prepareStatement(
"select * from xxl_job_lock where lock_name = 'schedule_lock' for update");
preparedStatement.execute();
# 触发任务调度 (伪代码)
for (XxlJobInfo jobInfo: scheduleList) {
  // 省略代码
}
# 事务提交
conn.commit();

调度线程会根据任务的「下次触发时间」,采取不同的动作:

已过期的任务需要立刻执行的,直接放入线程池中触发执行 ,五秒内需要执行的任务放到 ringData 对象里。

ringThread 启动后,定时从 ringData 对象里获取需要执行的任务列表 ,放入到线程池中触发执行。

5 自研在巨人的肩膀上

2018年,我有一段自研任务调度系统的经历。

背景是:兼容技术团队自研的RPC框架,技术团队不需要修改代码,RPC注解方法可以托管在任务调度系统中,直接当做一个任务来执行。

自研过程中,研读了XXL-JOB 源码,同时从阿里云分布式任务调度 SchedulerX 吸取了很多营养。

SchedulerX 1.0 架构图

  • Schedulerx-console 是任务调度的控制台,用于创建、管理定时任务。负责数据的创建、修改和查询。在产品内部与 schedulerx server 交互。
  • Schedulerx-server 是任务调度的服务端,是 Scheduler的核心组件。负责客户端任务的调度触发以及任务执行状态的监测。
  • Schedulerx-client 是任务调度的客户端。每个接入客户端的应用进程就是一个的 Worker。Worker 负责与 Schedulerx-server 建立通信,让 schedulerx-server发现客户端的机器。并向schedulerx-server注册当前应用所在的分组,这样 schedulerx-server才能向客户端定时触发任务。

我们模仿了SchedulerX的模块,架构设计如下图:

我选择了 RocketMQ 源码的通讯模块 remoting 作为自研调度系统的通讯框架。基于如下两点:

  1. 我对业界大名鼎鼎的 Dubbo不熟悉,而remoting我已经做了多个轮子,我相信自己可以搞定;
  2. 在阅读 SchedulerX 1.0 client 源码中,发现 SchedulerX 的通讯框架和RocketMQ Remoting很多地方都很类似。它的源码里有现成的工程实现,完全就是一个宝藏。

我将 RocketMQ remoting 模块去掉名字服务代码,做了一定程度的定制。

在RocketMQ的remoting里,服务端采用 Processor 模式。

调度中心需要注册两个处理器:回调结果处理器CallBackProcessor和心跳处理器HeartBeatProcessor 。执行器需要注册触发任务处理器TriggerTaskProcessor 。

public void registerProcessor(
             int requestCode,
             NettyRequestProcessor processor,
             ExecutorService executor);

处理器的接口:

public interface NettyRequestProcessor {
 RemotingCommand processRequest(
                 ChannelHandlerContext ctx,
                 RemotingCommand request) throws Exception;
 boolean rejectRequest();
}

对于通讯框架来讲,我并不需要关注通讯细节,只需要实现处理器接口即可。

以触发任务处理器TriggerTaskProcessor举例:

搞定网络通讯后,调度器如何设计 ?最终我还是选择了Quartz 集群模式。主要是基于以下几点原因:

  1. 调度量不大的情况下 ,Quartz 集群模式足够稳定,而且可以兼容原来的XXL-JOB任务;
  2. 使用时间轮的话,本身没有足够的实践经验,担心出问题。另外,如何让任务通过不同的调度服务(schedule-server)触发, 需要有一个协调器。于是想到Zookeeper。但这样的话,又引入了新的组件。
  3. 研发周期不能太长,想快点出成果。

自研版的调度服务花费一个半月上线了。系统运行非常稳定,研发团队接入也很顺畅。调度量也不大 ,四个月总共接近4000万到5000万之间的调度量。

坦率的讲,自研版的瓶颈,我的脑海里经常能看到。数据量大,我可以搞定分库分表,但 Quartz 集群基于行级锁的模式 ,注定上限不会太高。

为了解除心中的困惑,我写一个轮子DEMO看看可否work:

  1. 去掉外置的注册中心,调度服务(schedule-server)管理会话;
  2. 引入zookeeper,通过zk协调调度服务。但是HA机制很粗糙,相当于一个任务调度服务运行,另一个服务standby;
  3. Quartz 替换成时间轮 (参考Dubbo里的时间轮源码)。

这个Demo版本在开发环境可以运行,但有很多细节需要优化,仅仅是个玩具,并没有机会运行到生产环境。

最近读阿里云的一篇文章《如何通过任务调度实现百万规则报警》,SchedulerX2.0 高可用架构见下图:

image.png

文章提到:

每个应用都会做三备份,通过 zk 抢锁,一主两备,如果某台 Server 挂了,会进行 failover,由其他 Server 接管调度任务。

这次自研任务调度系统从架构来讲,并不复杂,实现了XXL-JOB的核心功能,也兼容了技术团队的RPC框架,但并没有实现工作流以及mapreduce分片。

SchedulerX 在升级到2.0之后基于全新的Akka 架构,这种架构号称 实现高性能工作流引擎,实现进程间通信,减少网络通讯代码。

在我调研的开源任务调度系统中,PowerJob 也是基于Akka 架构,同时也实现了工作流和MapReduce执行模式。

我对PowerJob 非常感兴趣,也会在学习实践后输出相关文章,敬请期待。

6 技术选型

首先我们将任务调度开源产品和商业产品 SchedulerX 放在一起,生成一张对照表:

Quartz 和 ElasticJob从本质上还是属于框架的层面。

中心化产品从架构上来讲更加清晰,调度层面更灵活,可以支持更复杂的调度(mapreduce动态分片,工作流)。

XXL-JOB 从产品层面已经做到极简,开箱即用,调度模式可以满足大部分研发团队的需求。简单易用 + 能打,所以非常受大家欢迎。

其实每个技术团队的技术储备不尽相同,面对的场景也不一样,所以技术选型并不能一概而论。

不管是使用哪种技术,在编写任务业务代码时,还是需要注意两点:

  • 幂等。当任务被重复执行的时候,或者分布式锁失效的时候,程序依然可以输出正确的结果;
  • 任务不跑了,千万别惊慌。查看调度日志,JVM层面使用Jstack命令查看堆栈,网络通讯要添加超时时间 ,一般能解决大部分问题。

7 写到最后

2015年其实是非常有趣的一年。ElasticJob 和 XXL-JOB 这两种不同流派的任务调度项目都开源了。

在 XXL-JOB 源码里,至今还保留着许雪里老师在开源中国的一条动态截图:

刚写的任务调度框架 ,Web动态管理任务,实时生效,热乎的。没有意外的话,明天中午推送到git.osc上去。哈哈,下楼炒个面加个荷包蛋庆祝下。

看到这个截图,内心深处竟然会有一种共情,嘴角不自禁的上扬。

我又想起:2016年,ElasticJob的作者张亮老师开源了sharding-jdbc 。我在github上创建了一个私有项目,参考sharding-jdbc的源码,自己实现分库分表的功能。第一个类名叫:ShardingDataSource,时间定格在 2016/3/29。

我不知道如何定义“有创造力的软件工程师”,但我相信:一个有好奇心,努力学习,乐于分享,愿意去帮助别人的工程师,运气肯定不会太差。



相关实践学习
快速体验阿里云云消息队列RocketMQ版
本实验将带您快速体验使用云消息队列RocketMQ版Serverless系列实例进行获取接入点、创建Topic、创建订阅组、收发消息、查看消息轨迹和仪表盘。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
分布式计算 并行计算 数据库
Schedulerx2.0分布式计算原理&最佳实践
1. 前言 Schedulerx2.0的客户端提供分布式执行、多种任务类型、统一日志等框架,用户只要依赖schedulerx-worker这个jar包,通过schedulerx2.0提供的编程模型,简单几行代码就能实现一套高可靠可运维的分布式执行引擎。
27748 2
|
5月前
|
机器学习/深度学习 人工智能 前端开发
终端里的 AI 编程助手:OpenCode 使用指南
OpenCode 是开源的终端 AI 编码助手,支持 Claude、GPT-4 等模型,可在命令行完成代码编写、Bug 修复、项目重构。提供原生终端界面和上下文感知能力,适合全栈开发者和终端用户使用。
44497 11
|
7月前
|
数据采集 Web App开发 人工智能
如何让AI“看懂”网页?拆解 Browser-Use 的三大核心技术模块
Browser-Use 是一种基于大语言模型(LLM)的浏览器自动化技术,通过融合视觉理解、DOM解析和动作预测等模块,实现对复杂网页任务的自主操作。它突破了传统固定选择器和流程编排的限制,具备任务规划与语义理解能力,可完成注册、比价、填报等多步骤操作。其核心功能包括视觉与HTML融合解析、多标签管理、元素追踪、自定义动作、自纠错机制,并支持任意LLM模型。Browser-Use标志着浏览器自动化从“规则驱动”向“认知驱动”的跃迁,大幅降低维护成本,提升复杂任务的处理效率与适应性。
3917 29
|
7月前
|
分布式计算 Java 关系型数据库
SpringBoot集成powerJob实战派
PowerJob 是全新一代分布式任务调度与计算框架,支持可视化管理、多种定时策略、丰富的执行模式(如单机、广播、Map/MapReduce),并提供工作流编排、在线日志、高可用及分布式计算能力,适用于定时任务、集群执行、延迟处理等场景。
1166 1
SpringBoot集成powerJob实战派
|
消息中间件 RocketMQ
如何保证RocketMQ消息有序?
如何保证RocketMQ消息有序?
|
存储 监控 数据可视化
常见的分布式定时任务调度框架
分布式定时任务调度框架用于在分布式系统中管理和调度定时任务,确保任务按预定时间和频率执行。其核心概念包括Job(任务)、Trigger(触发器)、Executor(执行器)和Scheduler(调度器)。这类框架应具备任务管理、任务监控、良好的可扩展性和高可用性等功能。常用的Java生态中的分布式任务调度框架有Quartz Scheduler、ElasticJob和XXL-JOB。
5380 66
|
11月前
|
Kubernetes Cloud Native 调度
《分布式任务调度框架深度对比:Quartz/XXL-JOB/Elastic-Job/PowerJob选型指南》​
根据IDC预测,到2025年全球将有75%的企业任务调度系统需要重构以适应云原生架构。技术雷达监测:定期关注CNCF技术趋势报告渐进式改造:从非核心业务开始验证新框架人才储备:重点培养具备K8s Operator开发能力的调度专家评估现有系统的云原生适配度在测试环境部署PowerJob 4.3.3参与CNCF调度技术社区讨论制定6个月框架迁移路线图(注:本文数据来自各框架官方路线图、CNCF年度报告及笔者压力测试结果,转载请保留出处)
2377 0
|
分布式计算 监控 大数据
任务调度scheduleX
【8月更文挑战第22天】
2497 0
|
负载均衡 NoSQL Java
任务调度系统就该这么设计(万能通用),稳的一批! 上
任务调度系统就该这么设计(万能通用),稳的一批!上
|
存储 Java 关系型数据库
分布式定时任务框架Quartz总结和实践(2)—持久化到Mysql数据库
本文主要介绍分布式定时任务框架Quartz集成SpringBoot持久化数据到Mysql数据库的操作,上一篇文章使用Quartz创建定时任务都是保存在内存中,如果服务重启定时任务就会失效,所以Quartz官方也提供将定时任务等信息持久化到Mysql数据库的功能,本文主要实现这种Quartz的这种使用方式。
2310 0
分布式定时任务框架Quartz总结和实践(2)—持久化到Mysql数据库

热门文章

最新文章