江湖车侠|的自实现高可用方案,妙妙妙,PowerJob

本文适合有Java基础知识的人群
HelloGitHub推出的《讲解开源项目》系列 。
碎碎念高可用放到今天已经不是一个新颖的词汇了 , 怎么实现高可用大家也已经了然于心 。 多实例部署+服务注册+服务发现这一套组合拳打下来 , 实现高可用那还不是分分钟的事情 。 所以很多人看到PowerJob的介绍页面中写了任意组件支持集群部署以实现高可用 , 想当然的以为也是走了上述的那套流程 。 然后看到系统依赖组件时 , 发现......emmm......zookeeper呢?没看着 。 那找找Nacos?emmm......也没找着......不仅没找着 , 还发现文档中明明白白的写着 , 最小依赖仅为关系型数据库 。 许多用户看到这里就有点百思不得其解了 , 正常来讲都会有两个疑惑 。
要做到分布式环境下的高可用 , 肯定是需要服务注册、服务发现这样的概念的 。 没有外部注册中心 , 说白了就是自己去实现了一套类似的机制 。 那为什么要怎么做呢?
其实答案很简单——成本 。 这个成本指的是用户的接入成本 。 对于一个需要部署的重型开源项目来说 , 每少一个外部依赖 , 就多一份潜在的用户 。 额外的系统依赖代表着额外的技术栈和额外的维护成本 , 如果企业本身没有这一套技术体系(比如没用到zookeeper) , 而PowerJob又强依赖zookeeper , 那大概率只能说再见喽~
第一个问题解决了 , 接下来进入第二个问题~
C/S架构下 , 如果目标是server和client可以相互联通的“高可用” , 那么实现起来其实非常容易 。
首先 , 启动多个server应用实例 , 集群部署 。 然后将多个server的IP地址统统填入worker的配置文件中 , worker启动时 , 随机找一个IP进行连接 , 失败则重试 。 一旦成功连接到某一台server , 就开始上报自己的地址信息 。 server通过持有这个信息也可以和worker进行通讯 。 如此一来 , 一个最简单版本的“高可用”集群就搭建完成了 。 但是......它真的可用吗?
任务调度需要保证唯一性 , 即某个任务在某一个时刻只能被一台机器调度 , 否则就会导致重复执行 。 而前文提及的方案中 , 每一台server都是完全等价的 , 因此只能依靠分布式锁来保证唯一性 , 即抢到锁的server执行调度 , 其他server只能充当战地采访人员 , 默默地边缘OB 。 这种方案下 , 无论部署多少台server , 系统整体的调度性能其实是固定的 , 多实例部署只能做到高可用 , 而不能做到高性能 。 server无法持有完整的worker集群信息 。 PowerJob的定位是任务调度中间件 , 旨在为企业下各部门各业务线提供精准的调度和分布式计算能力 。 因此肯定会有集群分组的概念 , 就像RocketMQ中存在ProducerGroup和ConsumerGroup一样 , PowerJob有着AppName的概念 。 一个AppName逻辑上对应了某个应用下的一组任务 , 物理上对应了这个应用所部署的集群 。 为了便于server统一管理以及一些额外功能的实现(分布式计算) , server持有某一个AppName下完整的集群信息是一个强诉求 , 而前文提及的“瞎猫撞上死耗子”式方案 , 显然没办法做到这一点 。基于以上两点 , 征途是星辰大海的PowerJob需要探索出一种更合理、更强大的高可用架构 。