目录
前言
RabbitMQ 是一个广泛使用的消息队列系统,具有强大的集群和高可用性特性。以下是有关 RabbitMQ 集群与高可用性方面的详细解析,涵盖了单节点与集群部署、镜像队列、以及分布式架构的部署策略和最佳实践。
单节点与集群部署
1.1. 单节点部署
定义:
RabbitMQ 的单节点部署是指在一台服务器上运行一个 RabbitMQ 实例。它适用于开发、测试环境或对高可用性要求不高的场景。
工作原理:
在单节点中,所有消息和队列都集中在一个 RabbitMQ 实例上。如果该实例出现故障,则会导致消息服务不可用。
优缺点:
-
优点:
- 简单易用,部署和管理成本低。
- 适合小规模应用和开发测试场景。
-
缺点:
- 没有冗余,存在单点故障风险。
- 扩展性差,难以应对高并发和大流量需求。
应用场景:
- 开发和测试环境。
- 对消息丢失或短暂服务中断容忍度较高的生产环境。
配置方式:
- 在单台服务器上安装 RabbitMQ。
- 通过管理插件或命令行工具进行简单的管理和监控。
示例:
- 使用 Docker 启动单节点 RabbitMQ:
docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:management
详细可参考之前的文章:
1.2. 集群部署
定义:
RabbitMQ 集群由多个 RabbitMQ 节点组成,这些节点协同工作以提供更高的可用性和可扩展性。
工作原理:
集群中的各个节点共享元数据,但消息存储在单个节点上(默认配置)。当一个节点出现故障时,集群中的其他节点仍然可以继续提供服务。
优缺点:
-
优点:
- 提高了系统的可靠性,减少单点故障。
- 支持横向扩展,能够处理更多的消息和更高的并发量。
-
缺点:
- 部署和管理相对复杂。
- 需要额外的网络和存储资源。
应用场景:
- 高可用性要求高的生产环境。
- 大流量、大并发的分布式系统。
配置方式一:
1. 创建网络
docker network create rabbitmq-network
创建一个 Docker 自定义网络,名为
rabbitmq-network
。此网络用于让各个 RabbitMQ 容器节点能够相互通信。Docker 网络确保节点之间的容器可以通过容器名互相访问,这对于集群的节点发现和通信至关重要
2. 启动节点1(磁盘节点)
# rabbitmq:3.12-management 镜像名:版本
docker run -d --hostname rabbit1 --name rabbit1 --network rabbitmq-network -e RABBITMQ_ERLANG_COOKIE='my_cookie' -e RABBITMQ_NODENAME=rabbit@rabbit1 -p 15672:15672 -p 5672:5672 rabbitmq:3.12-management
-d
:后台运行容器。--hostname rabbit1
:设置容器的主机名为rabbit1
,这是 RabbitMQ 节点的名称标识。--name rabbit1
:设置容器的名称为rabbit1
,用于 Docker 内部管理。--network rabbitmq-network
:将容器连接到前面创建的rabbitmq-network
网络中。-e RABBITMQ_ERLANG_COOKIE='my_cookie'
:设置 Erlang Cookie,用于节点间的身份验证,确保集群的安全性。-e RABBITMQ_NODENAME=rabbit@rabbit1
:设置 RabbitMQ 节点的名称为rabbit@rabbit1
,这个名称在集群中是唯一的。-p 15672:15672
和-p 5672:5672
:分别映射管理界面和 AMQP 协议的端口到宿主机上,允许外部访问。这是一个磁盘节点(默认),数据会保存在磁盘上。
3.启动节点2(RAM节点)
docker run -d --hostname rabbit2 --name rabbit2 --network rabbitmq-network -e RABBITMQ_ERLANG_COOKIE='my_cookie' -e RABBITMQ_NODENAME=rabbit@rabbit2 rabbitmq:3.12-management
与启动节点1类似,但不暴露端口,并且这个节点稍后会加入到集群中并设置为 RAM 节点。RAM 节点的数据存储在内存中,适合对性能要求高的场景。
4.将节点2加入集群
docker exec -it rabbit2 bash
rabbitmqctl stop_app
rabbitmqctl join_cluster rabbit@rabbit1
rabbitmqctl start_app
exit
docker exec -it rabbit2 bash
:进入rabbit2
容器的交互式终端。rabbitmqctl stop_app
:停止 RabbitMQ 应用,准备加入集群。rabbitmqctl join_cluster rabbit@rabbit1
:将rabbit2
节点加入到rabbit1
节点所在的集群中。rabbitmqctl start_app
:启动 RabbitMQ 应用,使节点成为集群的一部分。exit
:退出容器的交互式终端。
5.启动节点3(RAM节点)
docker run -d --hostname rabbit3 --name rabbit3 --network rabbitmq-network -e RABBITMQ_ERLANG_COOKIE='my_cookie' -e RABBITMQ_NODENAME=rabbit@rabbit3 rabbitmq:3.12-management
启动另一个 RAM 节点
rabbit3
,与启动节点2类似。
6.将节点3加入集群
docker exec -it rabbit3 bash
rabbitmqctl stop_app
rabbitmqctl join_cluster rabbit@rabbit1
rabbitmqctl start_app
exit
与节点2的加入过程相同,将
rabbit3
加入到集群中,使其成为集群的一部分
- 这组指令搭建了一个包含一个磁盘节点(rabbit1)和两个 RAM 节点(rabbit2 和 rabbit3)的 RabbitMQ 集群。
- 磁盘节点负责持久化数据,RAM 节点利用内存加快消息的处理速度。
- 每个节点通过指定的网络相互通信,并通过 Erlang Cookie 进行身份验证。
7.启动并访问
注:由于本次启动时并没有指定用户与密码,所以使用默认的guest/guest进行登录即可,也可以自己基于之前的文章 进行添加用户:
RabbitMQ日常运维指令集
配置方式二
使用 Docker Compose 部署一个简单的 RabbitMQ 集群是一种便捷的方法,可以轻松管理多个 RabbitMQ 节点。以下是详细的步骤,包括如何编写 docker-compose.yml
文件以及配置、启动集群的过程。
1. 准备 docker-compose.yml
文件
首先,创建一个名为 docker-compose.yml
的文件,该文件定义了 RabbitMQ 集群的服务配置:
version: '3.8'
services:
rabbit1:
image: rabbitmq:3.12-management
container_name: rabbit1
hostname: rabbit1
environment:
RABBITMQ_ERLANG_COOKIE: 'my_cookie'
RABBITMQ_NODENAME: 'rabbit@rabbit1'
ports:
- "15672:15672" # 管理界面端口
- "5672:5672" # AMQP 协议端口
networks:
- rabbitmq_network
volumes:
- rabbit1_data:/var/lib/rabbitmq
rabbit2:
image: rabbitmq:3.12-management
container_name: rabbit2
hostname: rabbit2
environment:
RABBITMQ_ERLANG_COOKIE: 'my_cookie'
RABBITMQ_NODENAME: 'rabbit@rabbit2'
networks:
- rabbitmq_network
volumes:
- rabbit2_data:/var/lib/rabbitmq
rabbit3:
image: rabbitmq:3.12-management
container_name: rabbit3
hostname: rabbit3
environment:
RABBITMQ_ERLANG_COOKIE: 'my_cookie'
RABBITMQ_NODENAME: 'rabbit@rabbit3'
networks:
- rabbitmq_network
volumes:
- rabbit3_data:/var/lib/rabbitmq
networks:
rabbitmq_network:
volumes:
rabbit1_data:
rabbit2_data:
rabbit3_data:
docker-compose.yml
文件说明
- version:
3.8
指定了 Docker Compose 文件的版本。- services: 定义了三个 RabbitMQ 服务
rabbit1
、rabbit2
和rabbit3
,分别对应三个节点。- image: 使用
rabbitmq:3-management
镜像,包含 RabbitMQ 和管理插件。- container_name: 每个服务对应的容器名称。
- hostname: 指定每个 RabbitMQ 节点的主机名,这对于集群中的节点名称是必要的。
- environment: 配置环境变量:
RABBITMQ_ERLANG_COOKIE
: Erlang Cookie,用于节点间的通信和认证。RABBITMQ_NODENAME
: 节点名称,必须唯一。- ports: 将 RabbitMQ 的管理界面和 AMQP 端口映射到宿主机上。
- networks: 使用自定义的
rabbitmq_network
网络,以确保各节点之间可以互相通信。- volumes: 为每个节点配置持久化存储,以便重启后数据不会丢失。
2.启动集群
在包含 docker-compose.yml
文件的目录下,运行以下命令以启动集群:
docker-compose up -d
此命令将在后台启动所有定义的 RabbitMQ 节点,并且这些节点将自动连接到同一个 Docker 网络
rabbitmq_network
。
验证集群
要验证集群是否正常运行,可以通过以下步骤:
检查服务状态
查看所有运行的容器,确保三个 RabbitMQ 容器都在运行:
docker ps
检查集群状态
进入 rabbit1
容器并检查集群状态:
docker exec -it rabbit1 bash
rabbitmqctl cluster_status
停止和删除集群
要停止并删除容器及其相关的网络和卷,运行以下命令:
docker-compose down -v
-v
选项将删除创建的卷,确保数据被清除。
镜像队列
1.定义与工作原理
镜像队列是指将主节点的队列内容同步到集群中的其他节点上。当消费者从队列消费消息时,消息会从主节点发送,镜像节点会同步地更新其状态。如果主节点出现故障,RabbitMQ 会自动将其中一个镜像节点提升为新的主节点,从而继续处理队列中的消息。
工作原理:
- 主队列(Master Queue):在集群中的某个节点上维护的队列。
- 镜像节点(Mirror Nodes):集群中的其他节点,它们会保持主队列的完整副本。
- 故障切换(Failover):当主队列所在节点宕机时,RabbitMQ 自动选择一个镜像节点作为新的主队列,并继续处理消息。
2. 配置镜像队列
镜像队列可以通过 RabbitMQ 的策略(Policy)来配置。在 RabbitMQ 中,策略通过正则表达式匹配队列名称,然后应用指定的配置项来控制镜像队列的行为。
配置镜像队列的步骤:
-
连接到 RabbitMQ 管理界面或通过命令行执行操作。
-
创建策略,指定要镜像的队列以及镜像的规则:
通过 RabbitMQ 管理界面:
- 进入 "Admin" 选项卡,选择 "Policies"。
- 创建新的策略,指定名称、匹配队列的正则表达式(如
^mirrored.*
)、配置镜像参数。
通过命令行:
rabbitmqctl set_policy ha-all "^mirrored.*" '{"ha-mode":"all"}'
-
以上命令的含义:
ha-all
:策略名称。^mirrored.*
:匹配队列名称的正则表达式,所有以mirrored
开头的队列都会应用该策略。{"ha-mode":"all"}
:指定将队列镜像到集群中的所有节点。
-
验证配置:
- 使用 RabbitMQ 管理界面查看队列状态,确认队列已被镜像。
- 或使用以下命令行查看队列详细信息:
rabbitmqctl list_queues name policy slave_pids
3.应用场景
镜像队列特别适用于以下场景:
- 高可用性要求高的系统:如金融、医疗等行业,需要保证消息不丢失且系统持续可用。
- 灾备系统:需要容灾功能,保证在某个节点宕机时,系统仍然可以正常运行。
- 关键任务应用:不能容忍消息丢失的业务逻辑。
4. 优缺点
优点:
- 高可用性:在节点故障时,自动故障切换确保队列的持续可用性。
- 数据冗余:消息会在多个节点上存储,有助于防止单点故障导致的数据丢失。
缺点:
- 性能开销:每条消息的操作都需要在多个节点间进行同步,可能会影响吞吐量和延迟。
- 资源消耗:由于数据在多个节点间复制,需要更多的存储和网络资源。
- 复杂性:配置和维护镜像队列相对复杂,特别是在集群规模较大时。
5. Java 示例
假设我们有一个需要镜像的队列,以下是使用 Java 和 Spring AMQP 创建并连接到一个镜像队列的示例。
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitConfig {
@Bean
public Queue mirroredQueue() {
return QueueBuilder.durable("mirrored.queue")
.withArgument("x-ha-policy", "all") // 配置为镜像队列
.build();
}
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
return new RabbitTemplate(connectionFactory);
}
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
return new RabbitAdmin(connectionFactory);
}
}
使用了 x-ha-policy
参数来配置队列为镜像队列
分布式部署
分布式部署意味着将 RabbitMQ 节点分布在不同的数据中心、地理位置或网络环境中。这种部署方式适用于需要跨多个地区或数据中心实现高可用性和容灾的场景。
1. 分布式部署的主要目标
- 容灾:确保在一个数据中心或地理位置发生故障时,系统仍然能够正常运行。
- 负载均衡:通过分布多个节点,均衡不同区域的请求负载。
- 数据局部化:为不同区域的用户提供更低延迟的服务。
2. 典型架构设计
分布式部署通常包括以下几种架构模式:
- 多集群架构:在不同的数据中心或地理位置各自运行一个独立的 RabbitMQ 集群,之间通过某种消息传递机制进行通信,如使用 Shovel 或 Federation 插件。
- 跨数据中心的集群:在不同的数据中心部署一个跨越数据中心的 RabbitMQ 集群,节点之间通过 WAN 网络进行同步。该方案适合低延迟且带宽足够的环境。
3. RabbitMQ 分布式部署的关键技术
3.1 Shovel 插件
Shovel 插件用于在两个不同的 RabbitMQ 实例或集群之间转发消息。它能有效地在跨网络的 RabbitMQ 实例之间传递消息。
示例配置:
# 在 rabbit1 节点上安装并配置 Shovel 插件
rabbitmq-plugins enable rabbitmq_shovel
rabbitmq-plugins enable rabbitmq_shovel_management
# 创建 Shovel 配置
rabbitmqctl set_parameter shovel my-shovel \
'{"src-uri": "amqp://user:pass@rabbit1/vhost", "src-queue": "queue1", "dest-uri": "amqp://user:pass@rabbit2/vhost", "dest-queue": "queue2"}'
Shovel 插件会从 queue1
拉取消息并转发到 queue2
,实现不同 RabbitMQ 实例之间的消息传递。
3.2 Federation 插件
Federation 插件允许不同的 RabbitMQ 集群通过逻辑链接进行消息传递。与 Shovel 不同,Federation 更适合跨地理位置的集群之间建立动态连接。
示例配置:
# 在 rabbit1 节点上启用 Federation 插件
rabbitmq-plugins enable rabbitmq_federation
rabbitmq-plugins enable rabbitmq_federation_management
# 配置 Federation Upstream
rabbitmqctl set_parameter federation-upstream my-upstream '{"uri":"amqp://user:pass@rabbit2/vhost"}'
# 配置 Federation Policy
rabbitmqctl set_policy my-federation ".*" \
'{"federation-upstream-set":"all"}'
Federation 插件会将消息从一个集群传递到另一个集群。
4. 部署策略和实践
4.1 地理分布式集群
在每个主要地区或数据中心部署一个 RabbitMQ 集群,使用 Federation 或 Shovel 在这些集群之间转发消息。这种策略可以为每个地区的用户提供低延迟服务,并且在一个地区发生故障时,其他地区的服务不受影响。
4.2 多租户架构
在分布式部署中,可以通过虚拟主机(vhost)隔离不同租户的数据和操作。不同租户可以在不同的数据中心有各自的 RabbitMQ 集群,Shovel 或 Federation 可以实现租户数据的跨区域同步。
4.3 数据局部化
根据用户地理位置,将用户请求路由到最近的数据中心。使用分布式 RabbitMQ 结构可以有效减少延迟,提升用户体验。
5. 分布式部署的挑战和解决方案
- 网络延迟:跨数据中心的通信会受到网络延迟的影响。解决方案包括在低延迟网络上部署节点,或使用本地缓存。
- 数据一致性:保证跨节点或集群的数据一致性是一个挑战。可以通过消息的持久化和确认机制来减少不一致的风险。
- 运维复杂性:分布式部署增加了运维的复杂性,需要更复杂的监控、报警和自动化工具来管理。
通过合理的架构设计和技术手段,可以有效地在不同网络环境下实现 RabbitMQ 的分布式部署,从而实现系统的高可用性、容灾和低延迟服务。
6.使用Docker Compose 实现分布式部署
在每个服务器上,创建一个 docker-compose.yml
文件,用于定义 RabbitMQ 服务的配置。假设我们有两台服务器 server1
和 server2
。
Server 1 的 docker-compose.yml
:
version: '3.7'
services:
rabbitmq1:
image: rabbitmq:3.12-management
container_name: rabbitmq1
hostname: rabbit1
environment:
- RABBITMQ_ERLANG_COOKIE=my_cookie
- RABBITMQ_DEFAULT_USER=user
- RABBITMQ_DEFAULT_PASS=password
ports:
- "15672:15672" # 管理界面
- "5672:5672" # AMQP 端口
networks:
- rabbitmq-network
networks:
rabbitmq-network:
driver: bridge
Server 2 的 docker-compose.yml
:
version: '3.7'
services:
rabbitmq2:
image: rabbitmq:3.12-management
container_name: rabbitmq2
hostname: rabbit2
environment:
- RABBITMQ_ERLANG_COOKIE=my_cookie
- RABBITMQ_DEFAULT_USER=user
- RABBITMQ_DEFAULT_PASS=password
ports:
- "15672:15672" # 管理界面
- "5672:5672" # AMQP 端口
networks:
- rabbitmq-network
networks:
rabbitmq-network:
driver: bridge
部署 RabbitMQ 实例
在 server1
和 server2
上分别运行以下命令来启动 RabbitMQ 服务:
docker-compose up -d
这将在每个服务器上启动一个 RabbitMQ 实例。
4. 配置 Shovel 插件或 Federation 插件
接下来,使用 Shovel 或 Federation 插件来连接这两个分布式的 RabbitMQ 实例。
使用 Shovel 插件配置消息传递
在 server1
上:
docker exec -it rabbitmq1 bash
rabbitmq-plugins enable rabbitmq_shovel
rabbitmq-plugins enable rabbitmq_shovel_management
rabbitmqctl set_parameter shovel my-shovel \
'{"src-uri": "amqp://user:password@rabbit1/vhost", "src-queue": "queue1", "dest-uri": "amqp://user:password@rabbit2/vhost", "dest-queue": "queue2"}'
在 server2
上:
docker exec -it rabbitmq2 bash
rabbitmq-plugins enable rabbitmq_shovel
rabbitmq-plugins enable rabbitmq_shovel_management
rabbitmqctl set_parameter shovel my-shovel \
'{"src-uri": "amqp://user:password@rabbit2/vhost", "src-queue": "queue2", "dest-uri": "amqp://user:password@rabbit1/vhost", "dest-queue": "queue1"}'
使用 Federation 插件配置消息传递
在 server1
上:
docker exec -it rabbitmq1 bash
rabbitmq-plugins enable rabbitmq_federation
rabbitmq-plugins enable rabbitmq_federation_management
rabbitmqctl set_parameter federation-upstream my-upstream \
'{"uri":"amqp://user:password@rabbit2/vhost"}'
rabbitmqctl set_policy my-federation ".*" \
'{"federation-upstream-set":"all"}'
在 server2
上:
docker exec -it rabbitmq2 bash
rabbitmq-plugins enable rabbitmq_federation
rabbitmq-plugins enable rabbitmq_federation_management
rabbitmqctl set_parameter federation-upstream my-upstream \
'{"uri":"amqp://user:password@rabbit1/vhost"}'
rabbitmqctl set_policy my-federation ".*" \
'{"federation-upstream-set":"all"}'
总结
- 单节点与集群部署:单节点适用于开发和测试环境,集群部署用于生产环境,提高了系统的可靠性和可扩展性。
- 镜像队列:为关键业务场景提供高可用性,确保消息在节点故障时不会丢失。
- 分布式架构:通过 Federation 和 Shovel 插件,RabbitMQ 可以在不同地理位置的集群间实现消息的传递,适用于复杂的分布式系统。