RabbitMQ 集群与高可用性

目录

单节点与集群部署

[1.1. 单节点部署](#1.1. 单节点部署)

[1.2. 集群部署](#1.2. 集群部署)

镜像队列

1.定义与工作原理

[2. 配置镜像队列](#2. 配置镜像队列)

3.应用场景

[4. 优缺点](#4. 优缺点)

[5. Java 示例](#5. Java 示例)

分布式部署

[1. 分布式部署的主要目标](#1. 分布式部署的主要目标)

[2. 典型架构设计](#2. 典型架构设计)

[3. RabbitMQ 分布式部署的关键技术](#3. RabbitMQ 分布式部署的关键技术)

[4. 部署策略和实践](#4. 部署策略和实践)

[5. 分布式部署的挑战和解决方案](#5. 分布式部署的挑战和解决方案)

[6.使用Docker Compose 实现分布式部署](#6.使用Docker Compose 实现分布式部署)

总结


前言

RabbitMQ 是一个广泛使用的消息队列系统,具有强大的集群和高可用性特性。以下是有关 RabbitMQ 集群与高可用性方面的详细解析,涵盖了单节点与集群部署、镜像队列、以及分布式架构的部署策略和最佳实践。

单节点与集群部署

1.1. 单节点部署

定义

RabbitMQ 的单节点部署是指在一台服务器上运行一个 RabbitMQ 实例。它适用于开发、测试环境或对高可用性要求不高的场景。

工作原理

在单节点中,所有消息和队列都集中在一个 RabbitMQ 实例上。如果该实例出现故障,则会导致消息服务不可用。

优缺点

  • 优点

    • 简单易用,部署和管理成本低。
    • 适合小规模应用和开发测试场景。
  • 缺点

    • 没有冗余,存在单点故障风险。
    • 扩展性差,难以应对高并发和大流量需求。

应用场景

  • 开发和测试环境。
  • 对消息丢失或短暂服务中断容忍度较高的生产环境。

配置方式

  • 在单台服务器上安装 RabbitMQ。
  • 通过管理插件或命令行工具进行简单的管理和监控。

示例

  • 使用 Docker 启动单节点 RabbitMQ:

    docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:management

详细可参考之前的文章:

RabbitMQ入门基础及使用Docker安装

1.2. 集群部署

定义

RabbitMQ 集群由多个 RabbitMQ 节点组成,这些节点协同工作以提供更高的可用性和可扩展性。

工作原理

集群中的各个节点共享元数据,但消息存储在单个节点上(默认配置)。当一个节点出现故障时,集群中的其他节点仍然可以继续提供服务。

优缺点

  • 优点

    • 提高了系统的可靠性,减少单点故障。
    • 支持横向扩展,能够处理更多的消息和更高的并发量。
  • 缺点

    • 部署和管理相对复杂。
    • 需要额外的网络和存储资源。

应用场景

  • 高可用性要求高的生产环境。
  • 大流量、大并发的分布式系统。

配置方式一

  1. 创建网络

    docker network create rabbitmq-network

创建一个 Docker 自定义网络,名为 rabbitmq-network。此网络用于让各个 RabbitMQ 容器节点能够相互通信。Docker 网络确保节点之间的容器可以通过容器名互相访问,这对于集群的节点发现和通信至关重要

  1. 启动节点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节点)

bash 复制代码
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加入集群

bash 复制代码
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节点)

bash 复制代码
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加入集群

bash 复制代码
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 集群的服务配置:

bash 复制代码
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 服务 rabbit1rabbit2rabbit3,分别对应三个节点。
  • 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 文件的目录下,运行以下命令以启动集群:

bash 复制代码
docker-compose up -d

此命令将在后台启动所有定义的 RabbitMQ 节点,并且这些节点将自动连接到同一个 Docker 网络 rabbitmq_network

验证集群

要验证集群是否正常运行,可以通过以下步骤:

检查服务状态

查看所有运行的容器,确保三个 RabbitMQ 容器都在运行:

bash 复制代码
docker ps

检查集群状态

进入 rabbit1 容器并检查集群状态:

bash 复制代码
docker exec -it rabbit1 bash
rabbitmqctl cluster_status

停止和删除集群

要停止并删除容器及其相关的网络和卷,运行以下命令:

bash 复制代码
docker-compose down -v

-v 选项将删除创建的卷,确保数据被清除。

镜像队列

1.定义与工作原理

镜像队列是指将主节点的队列内容同步到集群中的其他节点上。当消费者从队列消费消息时,消息会从主节点发送,镜像节点会同步地更新其状态。如果主节点出现故障,RabbitMQ 会自动将其中一个镜像节点提升为新的主节点,从而继续处理队列中的消息。

工作原理

  • 主队列(Master Queue):在集群中的某个节点上维护的队列。
  • 镜像节点(Mirror Nodes):集群中的其他节点,它们会保持主队列的完整副本。
  • 故障切换(Failover):当主队列所在节点宕机时,RabbitMQ 自动选择一个镜像节点作为新的主队列,并继续处理消息。
2. 配置镜像队列

镜像队列可以通过 RabbitMQ 的策略(Policy)来配置。在 RabbitMQ 中,策略通过正则表达式匹配队列名称,然后应用指定的配置项来控制镜像队列的行为。

配置镜像队列的步骤:

  1. 连接到 RabbitMQ 管理界面或通过命令行执行操作。

  2. 创建策略,指定要镜像的队列以及镜像的规则:

    通过 RabbitMQ 管理界面:

    • 进入 "Admin" 选项卡,选择 "Policies"。
    • 创建新的策略,指定名称、匹配队列的正则表达式(如 ^mirrored.*)、配置镜像参数。

    通过命令行:

bash 复制代码
rabbitmqctl set_policy ha-all "^mirrored.*" '{"ha-mode":"all"}'
  • 以上命令的含义:

    • ha-all:策略名称。
    • ^mirrored.*:匹配队列名称的正则表达式,所有以 mirrored 开头的队列都会应用该策略。
    • {"ha-mode":"all"}:指定将队列镜像到集群中的所有节点。
  • 验证配置

    • 使用 RabbitMQ 管理界面查看队列状态,确认队列已被镜像。
    • 或使用以下命令行查看队列详细信息:
bash 复制代码
rabbitmqctl list_queues name policy slave_pids
3.应用场景

镜像队列特别适用于以下场景:

  • 高可用性要求高的系统:如金融、医疗等行业,需要保证消息不丢失且系统持续可用。
  • 灾备系统:需要容灾功能,保证在某个节点宕机时,系统仍然可以正常运行。
  • 关键任务应用:不能容忍消息丢失的业务逻辑。
4. 优缺点

优点

  • 高可用性:在节点故障时,自动故障切换确保队列的持续可用性。
  • 数据冗余:消息会在多个节点上存储,有助于防止单点故障导致的数据丢失。

缺点

  • 性能开销:每条消息的操作都需要在多个节点间进行同步,可能会影响吞吐量和延迟。
  • 资源消耗:由于数据在多个节点间复制,需要更多的存储和网络资源。
  • 复杂性:配置和维护镜像队列相对复杂,特别是在集群规模较大时。
5. Java 示例

假设我们有一个需要镜像的队列,以下是使用 Java 和 Spring AMQP 创建并连接到一个镜像队列的示例。

java 复制代码
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 集群,之间通过某种消息传递机制进行通信,如使用 ShovelFederation 插件。
  • 跨数据中心的集群:在不同的数据中心部署一个跨越数据中心的 RabbitMQ 集群,节点之间通过 WAN 网络进行同步。该方案适合低延迟且带宽足够的环境。
3. RabbitMQ 分布式部署的关键技术

3.1 Shovel 插件

Shovel 插件用于在两个不同的 RabbitMQ 实例或集群之间转发消息。它能有效地在跨网络的 RabbitMQ 实例之间传递消息。

示例配置

bash 复制代码
# 在 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 更适合跨地理位置的集群之间建立动态连接。

示例配置

bash 复制代码
# 在 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 服务的配置。假设我们有两台服务器 server1server2

Server 1 的 docker-compose.yml:

bash 复制代码
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 2docker-compose.yml:

bash 复制代码
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 实例

server1server2 上分别运行以下命令来启动 RabbitMQ 服务:

bash 复制代码
docker-compose up -d

这将在每个服务器上启动一个 RabbitMQ 实例。

4. 配置 Shovel 插件或 Federation 插件

接下来,使用 ShovelFederation 插件来连接这两个分布式的 RabbitMQ 实例。

使用 Shovel 插件配置消息传递

server1 上:

bash 复制代码
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 上:

bash 复制代码
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 上:

bash 复制代码
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 上:

bash 复制代码
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 可以在不同地理位置的集群间实现消息的传递,适用于复杂的分布式系统。
相关推荐
鸠摩智首席音效师2 小时前
Docker 中如何限制CPU和内存的使用 ?
docker·容器
Michaelwubo2 小时前
Docker dockerfile镜像编码 centos7
运维·docker·容器
jingyu飞鸟2 小时前
centos-stream9系统安装docker
linux·docker·centos
好像是个likun3 小时前
使用docker拉取镜像很慢或者总是超时的问题
运维·docker·容器
来一杯龙舌兰5 小时前
【RabbitMQ】RabbitMQ保证消息不丢失的N种策略的思想总结
分布式·rabbitmq·ruby·持久化·ack·消息确认
玖疯子5 小时前
介绍 Docker 的基本概念和优势,以及在应用程序开发中的实际应用。
docker
暴富的Tdy5 小时前
【快速上手Docker 简单配置方法】
docker·容器·eureka
Karoku0666 小时前
【k8s集群应用】kubeadm1.20高可用部署(3master)
运维·docker·云原生·容器·kubernetes
豆豆豆豆变6 小时前
docker之compose篇
docker·容器·自动化运维
saynaihe7 小时前
安全地使用 Docker 和 Systemctl 部署 Kafka 的综合指南
运维·安全·docker·容器·kafka