前言
前面我们学了 RabbitMQ 的集群,虽然集群可以缓解服务器的压力,并且在有 RabbitMQ 挂掉的时候也不会对整个 RabbitMQ 服务产生很大的影响。但是呢有一个问题,就是当 RabbitMQ 节点挂掉之后,那么由该节点创建的队列中的消息也就都会消息,这时就会对服务产生较大的影响,为了解决这个问题就需要用到 “仲裁队列” 了。
什么是仲裁队列
仲裁队列(Quorum Queues)是RabbitMQ在3.8版本及以后引入的一种现代队列类型,它主要基于Raft共识算法实现了一个持久化、复制的FIFO(先进先出)队列。仲裁队列的设计目标是为了提供更安全、更简单、定义明确的故障处理语义,从而使用户在设计和操作系统时更加容易理解。使用仲裁队列可以在 RabbitMQ 节点间进行队列数据的复制,从而达到在一个节点宕机时,队列仍然可以提供服务的效果。
这是 RabbitMQ 仲裁队列的官方文档 https://www.rabbitmq.com/docs/quorum-queues
仲裁队列是RabbitMQ 3.8版本最重要的改动。 他是镜像队列的替代方案。 在RabbitMQ 3.8版本问世之前,镜像队列是实现数据高可用的唯一手段,但是它有一些设计上的缺陷,这也是RabbitMQ提供仲裁队列的原因。经典镜像队列已被弃用,并计划在将来版本中移除。如果当前使用经典镜像队列的RabbitMQ安装需要迁移,可以参考官方提供的迁移指南 https://www.rabbitmq.com/docs/migrate-mcq-to-qq。
仲裁队列与镜像队列的区别:
- 仲裁队列是RabbitMQ 3.8版本及以后引入的,旨在取代和优化原有的镜像队列功能。
- 仲裁队列在数据一致性和故障处理方面提供了更加清晰和可预测的语义。
- 仲裁队列在设计和实现上更加关注数据安全和可预测的恢复,因此在某些功能上与镜像队列存在差异。
既然提到了 Raft 共识算法,那么我们来了解一下什么是 Raft 共识算法。
Raft协议
Raft是一种用于管理和维护分布式系统一致性的协议,它是一种共识算法,旨在实现高可用性和数据的持久性。Raft通过在节点间复制数据来保证分布式系统中的一致性,即使在节点故障的情况下也能保证数据不会丢失。
在分布式系统中,为了消除单点故障提高系统可用性,通常会使用副本来进行容错,但这会带来另一个问题,即如何保证多个副本之间的一致性?
共识算法(Consensus Algorithm)就是用来解决这个问题的,它允许多个分布式节点就某个值或一系列值达成一致性协议。即使在一些节点发生故障、网络分区或其他问题的情况下,共识算法也能保证系统的一致性和数据的可靠性。
Raft 协议原文 https://web.stanford.edu/~ouster/cgi-bin/papers/raft-atc14
Raft 基本概念
Raft使用Quorum机制来实现共识和容错,即Raft集群的操作必须得到大多数(> N/2)节点的同意才能提交。
在分布式系统中,节点是指一个独立成员。当我们向Raft集群发起一系列读写操作时,集群内部会进行一系列复杂的操作来确保数据的一致性和可靠性。
Raft集群必须存在一个主节点(Leader),客户端向集群发起的所有操作都必须经由主节点处理。因此,Raft核心算法的第一部分就是选主(Leader Election)。没有主节点,集群就无法正常工作。首先,需要选出一个主节点,然后再考虑其他事情。
主节点会负责接收客户端发来的操作请求,将操作包装为日志,并同步给其他节点。在保证大部分节点都同步了本次操作后,就可以安全地给客户端回应了。这一部分工作在Raft核心算法中被称为日志复制(Log Replication)。
由于主节点的责任非常重大,所以只有符合条件的节点才可以当选主节点。为了保证集群对外展现的一致性,主节点在处理操作日志时也必须谨慎。这部分在Raft核心算法中被称为安全性(Safety)。
Raft算法将一致性问题分解为三个子问题:Leader选举、日志复制和安全性。
选主
下面详细介绍下Raft的选主过程:
当集群中没有主节点时(例如,所有节点都刚启动或主节点故障),或者当前主节点失去联系时(例如,网络分区或