重构支持多租户的XXL-JOB,如何实现多个逻辑集群的均衡选主

原创 吴就业 131 0 2021-11-23

本文为博主原创文章,未经博主允许不得转载。

本文链接:https://wujiuye.com/article/bb43d01b566f41e7b40544ecfe0fe74f

作者:吴就业
链接:https://wujiuye.com/article/bb43d01b566f41e7b40544ecfe0fe74f
来源:吴就业的网络日记
本文为博主原创文章,未经博主允许不得转载。

我们基于XXL-JOB的架构原理,重新架构设计了支持多租户横向扩展的分布式任务调度平台。本篇介绍如何实现多个逻辑集群(多个租户逻辑上是独立的集群)的均衡选主。

我们用过的很多中间件都有实现多分片自动均衡选主的功能。

如分布式数据库TiDB,其存储引擎TiKV基于Raft算法实现分布式数据一致性,TiKV可以看成是一个大型Map,通过MulitRaft将这个大的Map分成多个Region,每个Region使用一个Raft Group实现数据一致性。

因为一个Raft集群只能有Leader节点负责读写请求,也就是说,一个有N个节点的集群,也只有一个节点是负责工作的,其它节点只是备用节点,这显然是资源浪费,也无法通过横向扩展集群性能。因此TiKV使用Multi Raft支持集群横向扩展。

多逻辑集群是指将一个物理集群分成多个逻辑集群,每个逻辑集群只能有Leader负责工作。均衡选主则是实现将多个逻辑集群的Leader节点均衡分布在每个物理节点上,将集群扩容或缩容时,也能重均衡分布这些逻辑集群的Leader节点。

多个逻辑集群容易实现,难的是如何实现多逻辑Leader节点在物理节点上均衡分布。本篇分享的是笔者想到的一种比较简单方案。

在物理节点固定的情况下,我们可以控制多个逻辑集群按顺序完成选举,这样就能控制每次选举哪个节点可以成为Leader节点。但如果是动态添加物理节点,或者某个物理节点挂了,就很难做到将一部分逻辑集群的Leader节点转移到新的节点,或是将挂掉的部分逻辑集群的Leader节点平均分配到其它物理节点。

所以笔者想了另一种方案,将逻辑集群分为选举集群和业务集群,选举集群有且仅有一个,业务集群可以有n多个。在开始业务集群的选举之前,先完成选举集群的Leader节点选举。其它业务集群的选举则由选举集群的Leader节点负责。

选举集群也需要实现数据一致性,当选举集群的Leader节点挂掉时,其它选举集群的节点成为新的Leader时才能正确的知道当前所有业务集群的选举情况。

我们以使用zookeeper实现多逻辑集群均衡选主为例。

首先基于zookeeper实现选主功能,为选举集群选出一个Leader节点。

当业务集群启动选主时,先往/namespace/${cluster}/nodes路径注册业务集群节点的ip和端口信息。

选举Leader节点监听/namespace路径的子节点变化,为${cluster}业务集群选主,往/namespace/${cluster}/leader路径注册该业务集群的Leader节点,该业务集群的其它节点监听路径:/namespace/${cluster}/leader,监听到节点新增事件则为选主完成,并继续监听该路径,以便监听Leader变更。

当某些业务集群的Leader节点所在的物理节点挂掉时,选举集群的Leader节点将负责重新选主那些以挂掉的物理节点为业务集群Leader节点的业务集群。

当选举集群的Leader节点所在的物理节点挂掉时,新的选举集群的Leader节点将接替选举工作。

当新增物理节点时,选举集群的Leader节点将寻找一些业务集群,将这些业务集群的Leader节点转移到新增的物理节点上。

使用Zookeeper实现较为麻烦,如果是基于Raft实现,那将会简单很多。推荐开源的Raft算法实现SDK:SOFARaft。我们之所以选择zookeeper,有其它的原因。

思考题:为什么Redis Cluster使用的是分槽算法,而不是像采用Raft等分布式数据一致性算法实现?

笔者的观点:Redis实现的是缓存功能,追求接近本地内存的读写性能,而Raft等分布式数据一致性算法都要实现数据复制到多数节点,这里会有性能开销,因此分槽比多逻辑集群能带来更好的性能。

#中间件

声明:公众号、CSDN、掘金的曾用名:“Java艺术”,因此您可能看到一些早期的文章的图片有“Java艺术”的水印。

文章推荐

kafka消息重复消费排查

业务使用我们基础部门封装的kafka组件,在一次版本迭代中,我们引入了offset缓存,正是这个缓存,在某种条件触发下,会导致出现消息重复消费现象。

Quartz分布式调度原理

在同一时刻需要触发的Job只有少量的情况下,我们看不到Quartz的性能缺陷,在Job数量明显增加情况下,我们就会发现,调度延迟会有明显增加。尽管横向扩展节点,调度延迟也不会降低,且整体调度性能没有明显好转,反而更糟糕。

重构XXL-JOB,使用响应式编程实现异步RPC提升调度吞吐量

如果同一时刻需要下发几百个执行job的请求给执行器,使用这种阻塞的RPC,意味着需要开启几百个线程,使用几百个连接发送请求,而这几百个线程都需要阻塞等待响应,Job越多,需要的线程数就会越多,对调动中心的性能影响就越大。

BFE原生路由转发功能分析

为什么加上“原生”,因为我们基于BFE开发已经魔改了。路由转发是BFE作为一个七层流量代理服务的核心功能,BFE设计了一套支持多租户、多机房的路由转发模型。

基于Kafka,延迟消息队列的设计

由于Kafka不支持延迟消息,而目前公司技术栈中消息中间件使用的是Kafka,业务方希望使用RocketMQ满足延迟消息场景,但如果仅仅只是需要延迟消息功能而引入多一套消息中间件,这会增加运维与维护成本。在此背景下,我们希望通过扩展Kafka客户端提供延迟消息的支持。