RabbitMQ 集群

文章目录


集群搭建

参考:

  1. docker中安装并启动rabbitMQ

  2. Docker中搭建RabbitMQ集群

使用 Docker-Compose

这里提供一个脚本来使用 docker-compose 完成RabbitMQ集群的配置及启动

docker-compose.yml 文件如下

bash 复制代码
#!/bin/bash

# 定义 RabbitMQ 用户名、密码和 Erlang Cookie
RABBITMQ_USER="guest"
RABBITMQ_PASS="guest"
ERLANG_COOKIE="secret_cookie"

# 创建 docker-compose.yml 文件
cat << EOF > docker-compose.yml
version: '3.8'

services:
  rabbitmq1:
    image: rabbitmq:3-management
    hostname: rabbitmq1
    environment:
      RABBITMQ_DEFAULT_USER: $RABBITMQ_USER
      RABBITMQ_DEFAULT_PASS: $RABBITMQ_PASS
    ports:
      - "15671:15672"  # Management UI
      - "5671:5672"    # RabbitMQ
    volumes:
      - ./rabbitmq1/data:/var/lib/rabbitmq
      - ./rabbitmq1/etc/rabbitmq:/etc/rabbitmq
    networks:
      - rabbitmq-net

  rabbitmq2:
    image: rabbitmq:3-management
    hostname: rabbitmq2
    environment:
      RABBITMQ_DEFAULT_USER: $RABBITMQ_USER
      RABBITMQ_DEFAULT_PASS: $RABBITMQ_PASS
    ports:
      - "15672:15672"  # Management UI
      - "5672:5672"    # RabbitMQ
    volumes:
      - ./rabbitmq2/data:/var/lib/rabbitmq
      - ./rabbitmq2/etc/rabbitmq:/etc/rabbitmq
    networks:
      - rabbitmq-net

  rabbitmq3:
    image: rabbitmq:3-management
    hostname: rabbitmq3
    environment:
      RABBITMQ_DEFAULT_USER: $RABBITMQ_USER
      RABBITMQ_DEFAULT_PASS: $RABBITMQ_PASS
    ports:
      - "15673:15672"  # Management UI
      - "5673:5672"    # RabbitMQ
    volumes:
      - ./rabbitmq3/data:/var/lib/rabbitmq
      - ./rabbitmq3/etc/rabbitmq:/etc/rabbitmq
    networks:
      - rabbitmq-net

networks:
  rabbitmq-net:
EOF

echo "docker-compose.yml 文件已创建。"

# 创建节点目录结构
for i in {1..3}; do
    mkdir -p rabbitmq$i/data rabbitmq$i/etc/rabbitmq
    echo "NODENAME=rabbit@rabbitmq$i" > ./rabbitmq$i/etc/rabbitmq/rabbitmq-env.conf
    echo "$ERLANG_COOKIE" > ./rabbitmq$i/etc/rabbitmq/.erlang.cookie
    chmod 400 ./rabbitmq$i/etc/rabbitmq/.erlang.cookie  # 设置权限为 400
done

echo "各节点的配置文件已创建。"

# 启动 Docker Compose
docker-compose up -d

# 等待 RabbitMQ 启动
sleep 10

# 将节点加入集群
docker exec -it rabbitmq2 rabbitmqctl stop_app
docker exec -it rabbitmq2 rabbitmqctl join_cluster rabbit@rabbitmq1
docker exec -it rabbitmq2 rabbitmqctl start_app

docker exec -it rabbitmq3 rabbitmqctl stop_app
docker exec -it rabbitmq3 rabbitmqctl join_cluster rabbit@rabbitmq1
docker exec -it rabbitmq3 rabbitmqctl start_app

# 显示集群状态
docker exec -it rabbitmq1 rabbitmqctl cluster_status

echo "RabbitMQ 集群已成功启动。"

使用方式:

复制脚本内容到指定脚本文件,例如rabbitmq_cluster.sh,添加执行权限并执行

脚本解释

Erlang节点之间通过认证Erlang Cookie的方式来允许互相通信,所以要确保在每个节点中使用相同的 RABBITMQ_ERLANG_COOKIE 值,以便它们能够相互通信。新版本已经不建议通过环境变量设置 Erlang Cookie 了,会有警告信息

RABBITMQ_ERLANG_COOKIE env variable support is deprecated and will be REMOVED in a future version. Use the $HOME/.erlang.cookie file or the --erlang-cookie switch instead.

,建议在 home 目录下新建 .erlang.cookie 文件,在 每个节点的 .erlang.cookie 写入一致的字符串,注意 .erlang.cookie 文件的权限应该为 400。所以为了便于修改ErlangCookie,启动容器时要做好容器数据卷的映射。因为 /var/lib/rabbitmq 是 RabbitMQ home 目录和 data 目录,所以需要映射到宿主机

启动成功后:访问WEB控制台界面

镜像队列

如果 RabbitMQ 集群中只有一个 Broker 节点,那么该节点的失效将导致整体服务的临时性不可用,并且也可能会导致消息的丢失。可以将所有消息都设置为持久化,并且对应队列的durable属性也设置为true,但 是这样仍然无法避免由于缓存导致的问题:因为消息在发送之后和被写入磁盘井执行刷盘动作之间存在一 个短暂却会产生问题的时间窗。通过 publisherconfirm(发布确认) 机制能够确保客户端知道哪些消息己经存入磁盘,尽 管如此,一般不希望遇到因单点故障导致的服务不可用。

引入镜像队列(Mirror Queue)的机制,可以将队列镜像到集群中的其他 Broker 节点之上,如果集群中 的一个节点失效了,队列能自动地切换到镜像中的另一个节点上以保证服务的可用性。

搭建步骤

  1. 启动三台集群节点
  2. 随便找一个节点添加 policy(策略)

找到 Policies 部分。

点击 Add / update a policy 按钮。

参数解释:

  1. Name: policy的名称,用户自定义。
  2. Pattern: queue的匹配模式(正则表达式)。^表示所有队列都是镜像队列。
  3. Definition: 镜像定义,包括三个部分ha-sync-mode、ha-mode、ha-params。

ha-mode: 指明镜像队列的模式,有效取值范围为all/exactly/nodes。

  • all:表示在集群所有的代理上进行镜像。
  • exactly:表示在指定个数的代理上进行镜像,代理的个数由ha-params指定。
  • nodes:表示在指定的代理上进行镜像,代理名称通过ha-params指定。

ha-params: ha-mode模式需要用到的参数。

ha-sync-mode: 表示镜像队列中消息的同步方式,有效取值范围为:automatic,manually。

  • automatic:表示自动向master同步数据。
  • manually:表示手动向master同步数据。

Priority: 可选参数, policy的优先级。

在 rabbitmq2 上创建一个队列发送一条消息,队列存在镜像队列,如下图所示:

工作原理

https://www.rabbitmq.com/docs/3.13/ha#what-is-mirroring

多个RabbitMQ节点组成镜像队列的情况下,有一个节点会作为主节点,其他的节点就是从节点,也就是其镜像队列。镜像队列其是就是从节点的概念。

对主节点的写操作会被复制到其他镜像队列上,slave会准确地按照master执行命令的顺序进行命令执行,故slave与master上维护的状态应该是相同的。

故障转移:如果持有队列主副本的节点发生故障,RabbitMQ 会自动将一个镜像副本提升为新的主副本,从而确保消息的可用性。

优缺点

优点:

  1. 高可用性:通过在多个节点上维护队列副本,确保即使某个节点故障,消息仍然可用。
  2. 故障转移:故障发生时可以快速切换到其他节点,减少服务中断。
    缺点:
  3. 资源消耗:镜像队列会消耗更多的内存和存储资源,因为每个消息都需要在多个节点上存储副本。
  4. 性能开销:在高负载情况下,消息复制可能导致性能下降,增加网络流量和延迟。

使用镜像策略的注意事项

在设计系统时,必须权衡高可用性和资源消耗之间的平衡。

定期监控队列和节点的状态,以确保镜像队列正常运行。

根据业务需求灵活设置镜像策略,确保系统在不同场景下的可靠性和性能。

通过合理配置镜像策略,您可以在 RabbitMQ 集群中实现高可用性和容错能力,确保消息在故障情况下的可用性。

镜像策略

RabbitMQ 的镜像策略(也称为高可用性策略)用于确保队列在集群中的高可用性和容错性。镜像队列会在多个节点上维护相同的队列副本,这样即使某个节点发生故障,其他节点仍然可以提供服务。以下是关于镜像策略的详细解释:

  1. 通过管理控制台设置
  2. 通过 rabbitmqctl 命令行工具设置
bash 复制代码
rabbitmqctl set_policy ha-all "^.*" '{"ha-mode":"all"}'

镜像策略的类型

ha-mode:

  1. all: 所有队列副本都在集群中的所有节点上。
  2. exactly: 指定每个队列应该有的副本数量。
  3. nodes: 指定特定的节点列表作为镜像副本。

ha-params:与 ha-mode 配合使用的参数,具体含义取决于 ha-mode 的选择。

主从同步

rabbitmq的主从复制是异步的,但是rabbitmq并不存在mysql这种场景的丢数据(这句话不是说rabbitmq保证不丢数据)。在这里,我们来分析一下RabbitMQ的副本复制的过程。

首先,我们来说一下mysql和rabbitmq的使用接口是不同的,这时很关键的一点。mysql是同步的接口,也就是说client将sql发给server,server处理sql后将结果返回给client,在server返回client结果前,client不能发起下一个sql的请求。对于rabbitmq来说,访问接口是异步的。client(我们这里说的是publisher)向rabbitmq server publish一条消息,在默认的情况下server是不返回成功还是失败的,也就是说client在不到成功还是失败的情况下就可以发起下一个请求。如果client关心server是否成功处理完这条消息,可以开启confirm模式,server会异步的返回ack通知client消息投递成功还是失败。但是client仍然不必等待收到当前消息的ack就可以继续发下一条。

接下来,我们来说rabbitmq的主从复制过程。实际上,RabbitMQ主从之间的数据复制是异步的,但是在rabbitmq中不会出现mysql那种丢数据的情况,这是因为rabbitmq的接口也是异步的,主收到一条消息写入本地存储,然后在发起写入从的请求。当所有从写入成功后,主才会给client返回ack说这次写入成功了。所以可以看出,虽然rabbitmq的主从复制是异步的,但是并且不会出现mysql丢数据的场景。只要客户端收到ack,就说明这条消息已经写入主和从了。

所以需要强调的一点是,同步和异步并非是决定数据可靠性的关键点。客户端收到成功通知时,所有副本是否写入成功才是判断数据可靠的关键点。因为mysql的接口是同步,所以才需要在主从复制同步还是异步上做出选择。rabbitmq的接口本身就是异步的接口,所以rabbitmq的主从复制就自然而然的是异步的方式。

同步延迟

在 RabbitMQ 中,同步延迟可能会影响消息的处理速度和系统的整体性能。以下是一些常见的解决方案和优化策略,可以帮助减少 RabbitMQ 的同步延迟:

  1. 优化网络配置
    网络带宽:确保 RabbitMQ 节点之间有足够的带宽,特别是在高负载情况下。考虑使用更快的网络连接。
    网络延迟:尽量将 RabbitMQ 节点部署在同一数据中心内,以减少网络延迟。
  2. 调整队列和镜像策略
    使用适当的镜像策略:
    如果不需要所有节点都有队列的镜像,可以选择 ha-mode 设置为 exactly 或 nodes,以减少复制的数量。
    如果只需要部分节点有镜像,可以指定特定的节点。
    减少镜像数量:尽量减少每个队列的镜像副本数量,权衡高可用性和性能之间的关系。
  3. 使用流控
    设置队列流控:可以通过设置 x-max-length 或 x-max-length-bytes 限制队列的最大长度或大小,从而防止队列过长导致的延迟。
  4. 增加消费者数量
    水平扩展消费者:增加消费者实例的数量,确保消息能够更快地被处理和确认。确保消费者能够在多个节点上并行运行。
  5. 优化消息处理
    提高消息处理效率:检查消费者的处理逻辑,确保消息处理尽可能高效,避免在处理过程中出现瓶颈。
    批量处理消息:考虑使用批量确认(basic.ack)而不是单个确认,以减少确认的开销。
  6. 监控和调试
    使用监控工具:利用 RabbitMQ 的监控插件或其他监控工具(如 Prometheus、Grafana)监控系统性能,识别瓶颈。
    分析日志:查看 RabbitMQ 日志,识别可能导致延迟的错误或警告。
  7. 资源和配置优化
    调整 RabbitMQ 配置:根据系统需求调整 RabbitMQ 的配置参数,如内存、磁盘和 CPU 使用情况。
    增加节点资源:确保 RabbitMQ 节点有足够的 CPU 和内存资源,避免因资源不足导致的性能下降。
  8. 使用持久化
    选择适当的持久化策略:在消息持久化与性能之间进行权衡,确保消息持久化不会对性能产生负面影响。
  9. 负载均衡
    使用负载均衡策略:在多个消费者之间分配负载,确保没有单个消费者过载,从而提高处理能力。
    通过上述方法,您可以有效减少 RabbitMQ 的同步延迟,并提高系统的整体性能和可靠性。
相关推荐
茶杯梦轩20 小时前
从零起步学习RabbitMQ || 第三章:RabbitMQ的生产者、Broker、消费者如何保证消息不丢失(可靠性)详解
分布式·后端·面试
回家路上绕了弯3 天前
深入解析Agent Subagent架构:原理、协同逻辑与实战落地指南
分布式·后端
用户8307196840823 天前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
用户8307196840825 天前
RabbitMQ vs RocketMQ 事务大对决:一个在“裸奔”,一个在“开挂”?
后端·rabbitmq·rocketmq
初次攀爬者6 天前
RabbitMQ的消息模式和高级特性
后端·消息队列·rabbitmq
初次攀爬者8 天前
ZooKeeper 实现分布式锁的两种方式
分布式·后端·zookeeper
让我上个超影吧9 天前
消息队列——RabbitMQ(高级)
java·rabbitmq
塔中妖9 天前
Windows 安装 RabbitMQ 详细教程(含 Erlang 环境配置)
windows·rabbitmq·erlang
断手当码农9 天前
Redis 实现分布式锁的三种方式
数据库·redis·分布式
初次攀爬者9 天前
Redis分布式锁实现的三种方式-基于setnx,lua脚本和Redisson
redis·分布式·后端