RabbitMQ集群 - 仲裁队列、Raft协议(最详细的选举流程)

仲裁队列


概述

1)RabbitMQ 普通队列在一个节点宕机之后,其他节点无法读写宕机节点的队列,为了解决这个问题,引入了仲裁队列.

2)仲裁队列通过 Raft 协议,实现了不同节点间队列消息数据的复制,使得在 创建这个队列的节点 宕机时,其他节点仍然可以使用该队列进行服务.

Ps:仲裁队列时 RabbitMQ3.8 版本的重要改动,是 镜像队列 的替代方案(设计上有缺陷). 镜像队列已被弃用,并计划在将来的版本中移除.

Raft 协议

概述

在分布式系统中,为了解决单点问题,通常会使用副本(从节点)来进行容错,但这又引入了另外一个问题——“如何保证副本之间的一致性?”.

共识算法就是来解决这个问题的,它可以使得一些节点发生故障、网络分区或其他问题情况下,也能保证系统的一致性和数据可靠性,而 Raft 就是 共识算法 中的一种.

Raft 算法将一致性问题分解为三个子问题:Leader选举、日志复制、安全性

Ps:除了 Raft 还有很多其他的共识算法,例如 Paxos、Zab、Gossip

基本概念

1)节点角色
在 Raft 算法中,每个节点都有以下 3 个角色之一:

  • Leader(领导者):负责处理所有客户端的请求,并将这些请求作为日志,发送给所有的 Follower. Leader 会定期向所有 Follower 发送心跳消息,告诉他们 “我是领导,我还活着”,防止 Follower 进入选举流程.
  • Follower(跟随者):跟随者 不直接处理客户端请求,而是接受 Leader 发送的日志,并使用这些信息.
  • Candidate(候选者):当 跟随者 在一段时间内没有收到 Leader 的心跳消息,就会变成 Candidate,并开始进入选举流程.’

大致流程:所有节点在刚启动时都是 follow 状态,在一段时间内如果没有收到来自 leader 的心跳,就会从 follower 切换到 candidate,发起选举. 如果收到多个投票(> n/2,包括自己的一票),则切换到 leader 状态,然后一直工作到它发生异常为止.

2)任期(term)
从一次选举开始,到一个 leander 最后宕机,就是一次任期. 如果一次选举没有选出 leader,这个任期会以没有 leader 而结束.

每个节点会存储当前任期号(current term number),并且会随着每次选举成功后单调递增.
节点之间通信的时候会交换任期号:

  • 如果一个 跟随者 节点的 任期号 小于其他节点,他就会将自己的任期号更新为较大的那个值.
  • 如果一个 候选者 或 领导者 节点的 任期号过期了(请求当leader票 或 发送心跳包 时顺带判断),他就会立即回到 follower 状态.
  • 如果一个节点收到了带着过期的任期号的请求,那么他会拒绝这次请求.

例如新的主节点的任期号为2,而 旧的主节点恢复了连接(任期号为1),给其他节点发送信号,其他节点一看,比我还小,就不听他的,并且告诉旧主机点,现在已经是 任期号为2 的年代了,此时旧的主节点就会把修改自己的任期号为2,并且将自己修改为 Follower 的角色.

Raft 算法中服务器节点之间采用 RPC 进行通信,主要有两类 RPC 请求:

  • RequestVote RPCs:请求投票,由 候选者 在选举过程中发出.
  • AppendEntries RPCs:追加条目,由 leader 发出,用来做日志复制和提供心跳机制.

选举流程(重点)

选主(Leader election)就是在集群中选择出一个主节点来负责特定工作(类似于公司的领导).

Note:正常情况下,集群中只有一个 Leader,剩下的节点都是 follower.

1)服务器刚启动的时候,所有节点都是 follow 状态,如果 follower 在 选举超时时间(election timeout) 内没有收到来自 leader 的心跳(可能:没有选出 leader、leader 挂了、leader 与 follower之间网络故障),则会主从发起选举. 步骤如下:

  • 第一个超时的节点,自增当前任期号,然后切换为 候选人 状态,并先给自己投一票.
  • 以并行的方式给集群中其他节点发送一个 RequestVote RPCs. (想要得到其他人的投票)

在这个过程中,可能会出现三种结果(后面会细致说明这三种情况):

  1. 赢得选举,称为 Leader(包括自己的一票).
  2. 其他节点赢得选举,它自行切换到 follower.
  3. 在 选举超时时间 内没有凑够 > n/2 的票数,就会保持 候选人状态,重新发出选举.
    在这里插入图片描述
    其他节点收到票后,判断如果符合 任期要求,就会会按照先来先服务原则(first-come-first-served)值投给一个 候选人.
    投票之后,会将自己的 任期 和 候选人 一致.
    在这里插入图片描述

2)第一种情况:赢得选举后,新的 leader 会立即给所有节点发消息,避免其余节点触发新的选举.
在这里插入图片描述
3)第二种情况:其他节点赢得选举成为 Leader,并且收到了 Leader 的心跳包,判定任期符合要求,然后就会将自己转为 follower.
在这里插入图片描述
在这里插入图片描述
4)第三种情况:没有任何一个节点获得 半数投票. 例如所有 follower 同时变成 candidate,然后他们都给先给自己投一票,这样就没有 candidate 能超过半数投票了.

在这里插入图片描述

那岂不是形成了一个闭环(永远没有节点能超过半数投票)?

为了解决这个问题,Raft 采用随机选举超时时间. 选举时间会从一个 固定的区间(比如 150-300ms)种随机选择. 这样就可以确保大部分情况下不会发生所有人同时再次选举,发起拉票的情况.
在这里插入图片描述
在这里插入图片描述

Ps:Raft 在线演示地址 https://raft.github.io/

消息复制

每个仲裁队列都有多个副本,包含 一个主 和 多个从副本,每个 副本都在不同的 RabbitMQ 节点上.

客户端(生产者 和 消费者)只会和 主节点 进行交互,主节点 再将这些命令复制到 从节点. 当 主节点 下线,其中一个 从节点 就会被选举成为 主节点,继续提供服务.

当之前 挂掉的主节点 重新上线后,发现自己的任期号 小于 当前 Leader 的任期号,就会将自己变为 Follower.

仲裁队列的使用

MQ 管理平台

在这里插入图片描述

Spring AMQP

1)配置

spring:
  application:
    name: rabbitmq
  rabbitmq:
    host: env-base
    port: 5672
    username: root
    password: 1111

2)Bean

import com.cyk.rabbitmq.constants.MQConst
import org.springframework.amqp.core.Queue
import org.springframework.amqp.core.QueueBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration
class QuorumConfig {

    @Bean
    fun quorumQueue(): Queue = QueueBuilder
        .durable(MQConst.QUORUM_QUEUE)
        .quorum()
        .build()

}

3)生产者接口

@RestController
@RequestMapping("/mq")
class MQApi(
    private val rabbitTemplate: RabbitTemplate
) {

    @GetMapping
    fun quorum(): String {
        rabbitTemplate.convertAndSend("", MQConst.QUORUM_QUEUE, "quorum msg 1")
        return "ok"
    }

}

4)触发端点,效果如下:
在这里插入图片描述
可以看到 仲裁队列 Node 这里 rabbit@mq1 +2 有一个 +2 的字样,代表整个队列有 2 个镜像节点.
进去可以看到 Leader 和 其他从节点是谁.
在这里插入图片描述
此时,将创建 仲裁队列 的节点下线(docker stop mq1),观察其他节点仲裁队列的信息,发现依旧可以提供服务.
在这里插入图片描述
在这里插入图片描述

  • 17
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈亦康

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值