• 分布式任务调度(04)--自研


    1 背景

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

    研读XXL-JOB,同时从阿里云分布式任务调度 SchedulerX 吸取。

    img

    SchedulerX 1.0 架构图

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

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

    img

    选择 RocketMQ 源码的通讯模块 remoting 作为自研调度系统的通讯框架:阅读 SchedulerX 1.0 client 源码中,发现 SchedulerX 的通讯框架和RocketMQ Remoting很多地方都很类似。它的源码里有现成的工程实现。

    将 RocketMQ remoting 模块去掉名字服务代码,做定制。

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

    img

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

    public void registerProcessor(
                 int requestCode,
                 NettyRequestProcessor processor,
                 ExecutorService executor);1.2.3.4.
    
    • 1
    • 2
    • 3
    • 4

    处理器的接口:

    Explainpublic interface NettyRequestProcessor {
     RemotingCommand processRequest(
                     ChannelHandlerContext ctx,
                     RemotingCommand request) throws Exception;
     boolean rejectRequest();
    }1.2.3.4.5.6.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

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

    img

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

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

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

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

    2 实战

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

    img

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

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

    img

    文章提到:

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

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

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

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

    3 技术选型

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

    img

    Quartz 和 ElasticJob从本质属于框架。

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

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

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

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

    参考

    • https://xie.infoq.cn/article/ca1973d9c00fae8a747fd5b9f
    • https://www.51cto.com/article/707369.html
  • 相关阅读:
    GO语言之Goroutine和channel
    vscode 如何配置快速生成 vue3 模板
    动态域名解析
    树的基本操作(数据结构)
    web前端大作业:诗人文化网页主题网站【唐代诗人】纯HTML+CSS制作
    ET-B31H-M如何设置门锁开关门时间间隔?
    v-if与v-show造成部分元素丢失的问题——v-if复用元素问题
    FastDFS文件同步机制分析
    vulnhub靶机darkhole
    CMakelists.txt 编写语法说明
  • 原文地址:https://blog.csdn.net/qq_33589510/article/details/134270350