PowerJob 的自实现高可用方案,妙妙妙!

时间:2024-02-22 11:04:38

本文适合有 Java 基础知识的人群

作者:HelloGitHub-Salieri

HelloGitHub 推出的《讲解开源项目》系列。

碎碎念

高可用放到今天已经不是一个新颖的词汇了,怎么实现高可用大家也已经了然于心。多实例部署 + 服务注册 + 服务发现这一套组合拳打下来,实现高可用那还不是分分钟的事情。所以很多人看到 PowerJob 的介绍页面中写了任意组件支持集群部署以实现高可用,想当然的以为也是走了上述的那套流程。然后看到系统依赖组件时,发现......emmm...... Zookeeper 呢?没看着。那找找 Nacos ?emmm......也没找着......不仅没找着,还发现文档中明明白白的写着,最小依赖仅为关系型数据库。许多用户看到这里就有点百思不得其解了,正常来讲都会有两个疑惑。

首先,为什么不用注册中心呢?

要做到分布式环境下的高可用,肯定是需要服务注册、服务发现这样的概念的。没有外部注册中心,说白了就是自己去实现了一套类似的机制。那为什么要怎么做呢?

其实答案很简单——成本。这个成本指的是用户的接入成本。对于一个需要部署的重型开源项目来说,每少一个外部依赖,就多一份潜在的用户。额外的系统依赖代表着额外的技术栈和额外的维护成本,如果企业本身没有这一套技术体系(比如没用到 zookeeper),而 PowerJob 又强依赖 zookeeper,那大概率只能说再见喽~

第一个问题解决了,接下来进入第二个问题~

简单高“可用”

PowerJob 系统中的基础组件为调度服务器 server 和执行器 worker,server 负责调度定时任务,并派发到 worker 执行,是一个典型的 C/S 架构。

C/S 架构下,如果目标是 server 和 client 可以相互联通的“高可用”,那么实现起来其实非常容易。

首先,启动多个 server 应用实例,集群部署。然后将多个 server 的 IP 地址统统填入 worker 的配置文件中,worker 启动时,随机找一个 IP 进行连接,失败则重试。一旦成功连接到某一台 server,就开始上报自己的地址信息。server 通过持有这个信息也可以和 worker 进行通讯。如此一来,一个最简单版本的“高可用”集群就搭建完成了。但是......它真的可用吗?

答案显然是否定的(否则也不会有这篇文章了是不是~)。以上方案主要存在两个问题:

  1. 任务调度需要保证唯一性,即某个任务在某一个时刻只能被一台机器调度,否则就会导致重复执行。而前文提及的方案中,每一台 server 都是完全等价的,因此只能依靠分布式锁来保证唯一性,即抢到锁的 server 执行调度,其他 server 只能充当战地记者,默默地边缘 OB。这种方案下,无论部署多少台 server,系统整体的调度性能其实是固定的,多实例部署只能做到高可用,而不能做到高性能。
  2. server 无法持有完整的 worker 集群信息。PowerJob 的定位是任务调度中间件,旨在为企业下各部门各业务线提供精准的调度和分布式计算能力。因此肯定会有集群分组的概念,就像 RocketMQ 中存在 ProducerGroup 和 ConsumerGroup 一样,PowerJob 有着 AppName 的概念。一个 AppName 逻辑上对应了某个应用下的一组任务,物理上对应了这个应用所部署的集群。为了便于 server 统一管理以及一些额外功能的实现(分布式计算),server 持有某一个 AppName 下完整的集群信息是一个强诉求,而前文提及的“瞎猫撞上死耗子”式方案,显然没办法做到这一点。

基于以上两点,征途是星辰大海的 PowerJob 需要探索出一种更合理、更强大的高可用架构。

分组隔离

其实根据前面遇到的问题,这一套机制的雏形也差不多出来了。

server 既然需要持有某一个分组下完整的集群信息,那么可以顺其自然的想到,能不能让某一个分组的所有 worker 都连接到某一台 server 呢?一旦某个分组下所有机器全部连接到了某一台 server,那么其实这就形成了一个小型的子系统。虽然整个 PowerJob 系统中存在着多台 server 和多个 worker 集群,但是对于这个分组的运行来说,只要有这个分组对应的 worker 集群以及它们连接的那一台 server 就够了。那么在这个小型“子系统”内部,只存在着一台 server,也就不存在重复调度问题了(server 只调度连接到它的 AppName 下面的任务就能实现这一点)。

所以,经过一层层的剥丝抽茧,问题已经转化为了:如何让某个分组下的所有机器都连接到同一台 server 上去呢?

看到这个问题的时候,相信很多人会有和我当时一样的想法,那就是:就这?

“让所有机器都连接到同一台 server 上去,那也太简单了吧,你只配置一个 IP 不就行了吗?”

“配置一个 IP 怎么做高可用,怎么利用多台 server 资源?”