RabbitMQ 集群降配

发布于:2025-03-19 ⋅ 阅读:(16) ⋅ 点赞:(0)

摘要

背景:2025年云成本优化仍是技术团队的核心命题。当前需对遗留架构进行精细化治理,其中由前任架构师设计的RabbitMQ集群成为重点优化对象。该集群采用经典高可用架构,由3台阿里云ECS实例构成核心节点,并通过负载均衡(SLB)实现流量分发。然而,经监控分析发现,节点资源利用率长期低于40%,存在显著的配置冗余。在保障业务连续性的前提下,需通过降配调优实现成本节约。
自建RabbitMQ集群

ECS 配置:8C16G,CPU利用率 峰值18%, 内存峰值 25%
降配目标:平滑的将ECS节点降配至 2C8G
在这里插入图片描述

检查状态

1. 检查 RabbitMQ 服务状态

使用 systemctl 命令查看服务是否正在运行:

sudo systemctl status rabbitmq-server
  • 输出结果
    • 如果显示 active (running),表示服务已启动。
    • 如果显示 inactive (dead),表示服务未运行。

2. 检查 RabbitMQ 端口监听

RabbitMQ 默认监听 5672(AMQP 协议)和 15672(管理界面)端口:

# 使用 netstat 或 ss 命令检查端口
sudo netstat -tuln | grep -E '5672|15672'
# 或
sudo ss -tuln | grep -E '5672|15672'
  • 输出结果:如果有 LISTEN 状态的端口,说明服务正常。

3. 检查 RabbitMQ 管理插件是否启用

若需通过 Web 界面管理 RabbitMQ,需确认管理插件是否启用:

sudo rabbitmq-plugins list
  • 输出结果:查找 rabbitmq_management 是否标记为 [E*](已启用)。

4. 检查开机自启状态

确认 RabbitMQ 是否设置为开机自启:

sudo systemctl is-enabled rabbitmq-server
  • 输出结果
    • enabled:已设置开机自启。
    • disabled:未设置开机自启(可通过 sudo systemctl enable rabbitmq-server 启用)。

5. 确认集群高可用性

  • 镜像队列配置:确保所有业务队列已配置镜像策略(如 ha-mode: all 或指定副本数),避免单节点故障导致消息丢失。
    # 查看当前策略
    rabbitmqctl list_policies
    # 示例:设置所有队列在3个节点镜像
    rabbitmqctl set_policy ha-all "^" '{"ha-mode":"all"}'
    
  • 集群状态健康:确认所有节点状态为 running,且无网络分区问题。
    rabbitmqctl cluster_status
    

6. 检查使用该集群的服务是否做了断开重连

实操

1. 负载均衡配置

  • 设置待降配节点的权重:在负载均衡(如 SLB)中暂时设置待操作节点的流量权重为0,确保降配期间流量仅路由到其他节点。

2. 逐个节点降配(滚动操作)

2.1 停止 RabbitMQ 服务
sudo systemctl stop rabbitmq-server
  • 验证节点离线:检查集群状态,确认该节点已标记为 down
    rabbitmqctl cluster_status
    
2.2 调整 ECS 配置
  • 关机 ECS
  • 降配操作:通过 ECS 控制台或 API 调整实例规格(CPU/内存)。
  • 重启 ECS(如需):若配置变更需要重启,确保重启后网络和存储正常挂载。
2.3 恢复节点并重新加入集群
  • 启动 RabbitMQ
    sudo systemctl start rabbitmq-server
    
  • 重新加入集群:如果节点因 IP 或主机名变化无法自动加入,需手动操作(一般不需要重新加入)
    # 在新节点上重置 RabbitMQ 并重新加入集群
    rabbitmqctl stop_app
    rabbitmqctl reset
    rabbitmqctl join_cluster rabbit@<主节点主机名>
    rabbitmqctl start_app
    
  • 验证集群状态:确保节点状态为 running,且队列镜像同步完成。
2.4 恢复负载均衡流量
  • 将节点权重恢复,观察健康检查状态。

3. 全局监控与验证

  • 业务监控:观察消息堆积、消费延迟、连接数等指标。
  • 集群同步状态:检查镜像队列同步进度。
    rabbitmqctl list_queues name messages_ready messages_unacknowledged
    
  • 日志检查:排查降配节点是否有异常报错。
    tail -f /var/log/rabbitmq/rabbit@*.log
    

4. 降配后优化(可选)

  • 调整内存阈值:根据新配置优化 RabbitMQ 内存限制(vm_memory_high_watermark)。
  • 磁盘空间监控:确保降配后的磁盘容量足够(RabbitMQ 默认需至少 50MB 剩余空间)。

风险点与应对

  1. 同步延迟:降配节点重启后,若队列数据量大,同步时间可能较长。建议在低峰期操作。
  2. 配置兼容性:确保新规格满足 RabbitMQ 最低要求(如内存不低于 1GB)。
  3. 网络波动:降配期间若节点 IP 变化,需更新集群节点列表和负载均衡配置。

总结

通过 逐节点滚动降配 + 负载均衡流量切换,可实现业务无感知。关键点在于确保镜像队列冗余、集群健康状态,以及操作顺序的严谨性。建议先在测试环境模拟流程,再在生产环境执行。

命令说明

查看集群状态命令 rabbitmqctl cluster_status

输出结果解析

Cluster status of node rabbit@rabbitmq-prod-03 ...
[{nodes,[{disc,['rabbit@rabbitmq-prod-01','rabbit@rabbitmq-prod-02',
                'rabbit@rabbitmq-prod-03']}]},
 {running_nodes,['rabbit@rabbitmq-prod-02','rabbit@rabbitmq-prod-01',
                 'rabbit@rabbitmq-prod-03']},
 {cluster_name,<<"rabbit@rabbitmq-prod-01">>},
 {partitions,[]},
 {alarms,[{'rabbit@rabbitmq-prod-02',[]},
          {'rabbit@rabbitmq-prod-01',[]},
          {'rabbit@rabbitmq-prod-03',[]}]}].
1. 集群节点状态
  • 所有节点均在线
    • {nodes} 列表显示集群包含 3 个磁盘节点(disc 类型):rabbit@rabbitmq-prod-01, rabbit@rabbitmq-prod-02, rabbit@rabbitmq-prod-03
    • {running_nodes} 列表显示这 3 个节点当前都在运行。
2. 网络分区
  • 无网络分区
    • {partitions,[]} 表示没有发生网络分区问题。如果存在分区,partitions 字段会列出被隔离的节点及其分区信息。
3. 告警状态
  • 无告警
    • {alarms,[{'rabbit@rabbitmq-prod-02',[]}, {'rabbit@rabbitmq-prod-01',[]}, {'rabbit@rabbitmq-prod-03',[]}]} 表明所有节点均未触发任何告警(如内存、磁盘空间不足等)。
4. 集群名称
  • 集群名称一致
    • {cluster_name,<<"rabbit@rabbitmq-prod-01">>} 显示集群的名称为 rabbit@rabbitmq-prod-01,所有节点共享同一个集群名称,表明它们属于同一集群。

健康状态总结

从上述分析来看,你的 RabbitMQ 集群处于健康状态

  1. 所有节点都在线且正常运行。
  2. 没有网络分区问题。
  3. 没有任何节点触发告警。
  4. 集群名称一致,结构完整。

进一步验证建议

虽然当前状态健康,但为了确保长期稳定运行,可以执行以下检查:

1. 检查队列镜像状态

确认队列是否在多个节点上正确镜像:

rabbitmqctl list_queues name pid slave_pids synchronised_slave_pids
  • 确保关键队列的 slave_pidssynchronised_slave_pids 包含至少 2 个节点。
2. 检查资源使用情况

监控节点的 CPU、内存和磁盘使用率,避免因资源不足导致性能下降或告警:

# 查看磁盘剩余空间
df -h

# 查看内存使用情况
free -m

# 查看 RabbitMQ 内存使用
rabbitmqctl status | grep -A 5 "memory"
3. 检查日志

查看 RabbitMQ 日志文件,排查潜在的警告或错误:

tail -n 20 /var/log/rabbitmq/rabbit@*.log
4. 监控连接数

确保各节点的连接数在合理范围内:

rabbitmqctl list_connections --node rabbit@rabbitmq-prod-03 | grep -v "Listing" | wc -l

查看节点同步状态 rabbitmqctl list_queues name pid slave_pids synchronised_slave_pids

命令输出解析
以下是 rabbitmqctl list_queues name pid slave_pids synchronised_slave_pids 的输出示例:

name: collector_event
pid: <rabbit@rabbitmq-prod-03.1606707793.6080.60>
slave_pids: [<rabbit@rabbitmq-prod-02.1607654826.19286.68>, <rabbit@rabbitmq-prod-01.1606707802.17230.4475>]
synchronised_slave_pids: [<rabbit@rabbitmq-prod-01.1606707802.17230.4475>, <rabbit@rabbitmq-prod-02.1607654826.19286.68>]
字段含义
  1. name

    • 队列名称。例如:collector_event
  2. pid

    • 主队列所在节点的进程 ID(Process ID)。例如:<rabbit@rabbitmq-prod-03.1606707793.6080.60> 表示主队列位于 rabbit@rabbitmq-prod-03 节点。
  3. slave_pids

    • 副本队列所在的节点和进程 ID 列表。例如:
      • <rabbit@rabbitmq-prod-02.1607654826.19286.68> 表示该副本位于 rabbit@rabbitmq-prod-02
      • <rabbit@rabbitmq-prod-01.1606707802.17230.4475> 表示该副本位于 rabbit@rabbitmq-prod-01
  4. synchronised_slave_pids

    • 已完成数据同步的副本队列所在的节点和进程 ID 列表。例如:
      • <rabbit@rabbitmq-prod-01.1606707802.17230.4475><rabbit@rabbitmq-prod-02.1607654826.19286.68> 表示这两个副本已完成同步。

如何判断镜像同步完成
  1. 比较 slave_pidssynchronised_slave_pids

    • 如果 synchronised_slave_pids 包含所有 slave_pids 中的节点,则表示所有副本均已同步完成。
    • 示例分析
      • slave_pids: [<rabbit@rabbitmq-prod-02>, <rabbit@rabbitmq-prod-01>]
      • synchronised_slave_pids: [<rabbit@rabbitmq-prod-01>, <rabbit@rabbitmq-prod-02>]
      • 结论synchronised_slave_pids 包含了所有 slave_pids,说明镜像已完全同步。
  2. 检查数量是否一致

    • 如果 slave_pidssynchronised_slave_pids 的数量相同,且内容一致,则镜像同步完成。
  3. 异常情况

    • 如果 synchronised_slave_pids 为空或少于 slave_pids,则表示某些副本尚未完成同步,需等待同步完成后再继续操作。可以到管理界面queue界面查看有哪些队里没有同步完成,可点击进入队列并手动同步。

删除队列

rabbitmqctl delete_queue -p  <host>  <queue_name>
在 RabbitMQ 中执行删除队列(delete_queue)操作时,如果出现 Access refused 错误,通常是由于权限问题导致的。以下是可能的原因及解决方法:
1. 用户权限不足

RabbitMQ 的用户权限分为三类:

  • Configure:允许创建和删除队列、交换器等资源。
  • Write:允许向队列发送消息。
  • Read:允许从队列消费消息。
检查用户权限

使用以下命令查看当前用户的权限:

rabbitmqctl list_permissions -p <vhost>
  • <vhost> 是目标虚拟主机,默认为 /
  • 输出示例:
    Listing permissions for vhost "/" ...
    user    configure   write   read
    guest   .*          .*      .*
    
解决方法

确保当前用户对目标队列所在的虚拟主机具有足够的权限:

# 授予用户对虚拟主机的权限
rabbitmqctl set_permissions -p <vhost> <username> ".*" ".*" ".*"
  • <username>:当前登录 RabbitMQ 的用户名。
  • "."*:表示匹配所有资源。

2. 队列被其他消费者占用

如果队列正在被其他消费者使用(例如有活跃的连接或未确认的消息),删除操作可能会失败。

解决方法
  • 停止消费者:确保没有客户端正在消费该队列。
  • 清空队列(可选):
    rabbitmqadmin delete queue name=<queue_name>
    
    或通过管理界面清空队列。

3. 用户未绑定到正确的虚拟主机

RabbitMQ 支持多虚拟主机(vhost)。如果用户未绑定到目标队列所在的虚拟主机,也会导致权限拒绝。

检查虚拟主机

列出所有虚拟主机:

rabbitmqctl list_vhosts
解决方法

将用户添加到正确的虚拟主机,并授予权限:

# 添加用户到虚拟主机
rabbitmqctl add_user <username> <password>
rabbitmqctl set_permissions -p <vhost> <username> ".*" ".*" ".*"