主版本升级(蓝绿部署)

RabbitMQ 3.12.x 不能通过原地升级直接升级到 4.2.x。您需要创建一个新的 4.2.x 实例,并从旧实例迁移数据。本文档根据是否可接受停机,提供两种迁移方案。

选择您的方案
  • 选项 1:清空并迁移 — 如果您可以容忍短暂的服务中断,请先消费完所有消息,然后切换到新实例。这是最简单的方案。
  • 选项 2:蓝绿升级 — 如果您不能接受停机,请使用 Federation 插件 以实现零消息丢失的无缝迁移。

选项 1:清空并迁移(可接受停机)

此方案会带来短暂的服务中断。如果您的业务可以容忍停机,这是最直接的方案:

  1. 清空消息: 停止所有生产者,并等待消费者处理完所有剩余消息。确保所有队列都为空。
  2. 导出定义: 从旧的 3.12.x 实例导出定义(exchanges、queues、bindings、users、vhosts)。
  3. 创建新实例: 部署一个新的 RabbitMQ 4.2.x 实例。
  4. 导入定义: 将定义导入新的 4.2.x 实例。
  5. 切换流量: 更新应用配置以连接到新实例,并重启应用。
  6. 下线: 在确认一切运行正常后,删除旧的 3.12.x 实例。

选项 2:蓝绿升级(零停机)

此方案使用 RabbitMQ Federation 插件 将消息从旧实例(蓝色)无缝传输到新实例(绿色),而无需停止生产者或消费者。更多详情请参阅 官方蓝绿部署指南

工作原理

  1. 在现有的 3.12.x 实例(蓝色)旁边部署新的 4.2.x 实例(绿色)。
  2. 将蓝色实例的定义导入绿色实例(exchanges、queues、bindings、users 等)。
  3. 绿色 集群上配置 队列联邦,并将上游指向 蓝色
  4. 消费者 迁移到绿色实例——Federation 会自动将消息从蓝色拉取到绿色。
  5. 清空蓝色实例中的剩余消息。
  6. 生产者 迁移到绿色实例。
  7. 下线蓝色集群。
Federation 原理

联邦队列的工作原理是:只要蓝色集群上这些队列没有本地消费者,连接到绿色集群的消费者就会接收发布到蓝色集群的消息。本地消费者始终具有优先级。

前提条件

  • 旧的 RabbitMQ 3.12.x 实例(蓝色)运行正常,并处于 Active 状态。
  • 两个实例中都可用 rabbitmq_federation 插件。

操作步骤

CLI

步骤 1:创建新的 4.2.x 实例(绿色集群)

cat << 'EOF' | kubectl -n <namespace> create -f -
apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
  name: <green-instance-name>
spec:
  replicas: 3
  version: "4.2"
  resources:
    limits:
      cpu: 1
      memory: 2Gi
    requests:
      cpu: 1
      memory: 2Gi
  persistence:
    storage: 1Gi
    storageClassName: <storage-class>
  service:
    type: ClusterIP
  rabbitmq:
    additionalPlugins:
      - rabbitmq_federation
      - rabbitmq_federation_management
    additionalConfig: |-
      channel_max=1000
      default_vhost=/
      handshake_timeout=10000
      heartbeat=60
      max_message_size=134217728
      queue_index_embed_msgs_below=4096
      raft.wal_max_size_bytes=64000000
      vm_memory_calculation_strategy=allocated
      vm_memory_high_watermark.relative=0.4
EOF

等待绿色实例变为 Active

kubectl -n <namespace> get rabbitmqclusters <green-instance-name> -w

步骤 2:从蓝色实例导出定义并导入到绿色实例

# Export definitions from blue
kubectl exec -n <namespace> <blue-pod-0> -- \
  rabbitmqctl export_definitions /tmp/definitions.json

# Copy to local
kubectl cp <namespace>/<blue-pod-0>:/tmp/definitions.json ./definitions.json

# Copy to green pod
kubectl cp ./definitions.json <namespace>/<green-pod-0>:/tmp/definitions.json

# Import definitions into green
kubectl exec -n <namespace> <green-pod-0> -- \
  rabbitmqctl import_definitions /tmp/definitions.json

验证定义是否已正确导入:

# Check exchanges, queues, and bindings on green
kubectl exec -n <namespace> <green-pod-0> -- rabbitmqctl list_exchanges name type
kubectl exec -n <namespace> <green-pod-0> -- rabbitmqctl list_queues name
kubectl exec -n <namespace> <green-pod-0> -- rabbitmqctl list_bindings

步骤 3:在绿色集群上配置 Federation 上游

先获取蓝色集群的内部服务地址:

kubectl -n <namespace> get svc -l app.kubernetes.io/name=<blue-instance-name>

然后获取蓝色集群的凭据:

# Get the default user secret name
kubectl -n <namespace> get rabbitmqclusters <blue-instance-name> \
  -o jsonpath='{.status.defaultUser.secretReference.name}'

# Retrieve username and password
BLUE_USER=$(kubectl -n <namespace> get secret <blue-secret-name> \
  -o jsonpath='{.data.username}' | base64 -d)
BLUE_PASS=$(kubectl -n <namespace> get secret <blue-secret-name> \
  -o jsonpath='{.data.password}' | base64 -d)

echo "Blue cluster credentials: $BLUE_USER / $BLUE_PASS"
URL 编码

如果您的用户名或密码包含特殊字符(例如 @:/),请确保它们在下面的连接 URI 中已进行 URL 编码。

绿色 集群上配置指向 蓝色 的上游:

kubectl exec -n <namespace> <green-pod-0> -- \
  rabbitmqctl set_parameter federation-upstream blue \
  '{"uri":"amqp://<blue-user>:<blue-password>@<blue-service-name>.<namespace>.svc.cluster.local"}'

设置一个 Federation 策略以匹配所有队列:

kubectl exec -n <namespace> <green-pod-0> -- \
  rabbitmqctl set_policy --apply-to queues blue-federation ".*" \
  '{"federation-upstream":"blue"}'
策略优先级说明

在 RabbitMQ 中,如果多个策略匹配同一个队列,则只会应用优先级最高的那个。如果您导入的定义中已经包含覆盖这些队列的策略,上面的全局 blue-federation 策略可能不会生效(或者如果其优先级更高,可能会覆盖现有规则)。

在这种情况下,您应该手动更新绿色集群上的现有策略,在保留当前定义的同时,添加 "federation-upstream": "blue" 键。

验证 Federation 状态:

kubectl exec -n <namespace> <green-pod-0> -- rabbitmqctl eval \
  'rabbit_federation_status:status().'

步骤 4:将消费者迁移到绿色集群

将消费者应用配置更新为指向绿色集群的服务地址。此时:

  • 生产者仍然向 蓝色 集群发布消息。
  • 消费者从 绿色 集群读取消息。
  • Federation 会自动将消息从蓝色拉取到绿色。

您可以使用以下命令获取绿色集群的服务地址:

# Get the green cluster's service address
kubectl -n <namespace> get svc -l app.kubernetes.io/name=<green-instance-name>

验证消息是否正在被转发:

# Check that consumers on green are receiving messages
kubectl exec -n <namespace> <green-pod-0> -- \
  rabbitmqctl list_queues name messages consumers

# Check federation link status
kubectl exec -n <namespace> <green-pod-0> -- \
  rabbitmqctl eval 'rabbit_federation_status:status().'
重要

在将消费者从蓝色集群迁移出去之前,请确保绿色集群上的 Federation 链路处于 running 状态。如果链路未运行,消息将不会传输。

步骤 5:清空蓝色集群中的消息

当所有消费者都迁移到绿色实例后,Federation 会清空蓝色实例中的剩余消息。监控进度:

# Watch queue message counts on blue decrease to 0
kubectl exec -n <namespace> <blue-pod-0> -- \
  rabbitmqctl list_queues name messages

如果积压较多,您也可以选择使用 Shovel 插件来加速清空:

# Enable shovel on green if not already enabled
kubectl exec -n <namespace> <green-pod-0> -- rabbitmq-plugins enable rabbitmq_shovel

# Create a shovel for a specific queue with large backlog
kubectl exec -n <namespace> <green-pod-0> -- \
  rabbitmqctl set_parameter shovel shovel-blue-queue1 \
  '{"src-protocol":"amqp091","src-uri":"amqp://<blue-user>:<blue-password>@<blue-service-name>.<namespace>.svc.cluster.local","src-queue":"<queue-name>","dest-protocol":"amqp091","dest-uri":"amqp://","dest-queue":"<queue-name>"}'
说明

结合 Federation 同时使用 Shovel 会并行传输消息,这可能导致消息到达顺序发生变化。如果消息顺序非常重要,请仅依赖 Federation。

步骤 6:将生产者迁移到绿色集群

当蓝色集群上的队列接近为空时:

  1. 停止所有生产者。

  2. 等待剩余消息通过 Federation 完全清空。

  3. 验证蓝色集群上的所有队列都为空:

    kubectl exec -n <namespace> <blue-pod-0> -- \
      rabbitmqctl list_queues name messages
  4. 更新生产者配置以指向绿色集群,并重启它们。

步骤 7:清理并下线蓝色集群

从绿色集群中移除 Federation 策略和上游配置:

kubectl exec -n <namespace> <green-pod-0> -- \
  rabbitmqctl clear_policy blue-federation

kubectl exec -n <namespace> <green-pod-0> -- \
  rabbitmqctl clear_parameter federation-upstream blue

删除蓝色集群:

kubectl -n <namespace> delete rabbitmqcluster <blue-instance-name>

验证清单

使用以下清单验证迁移的每个阶段。每一步都包含可直接执行的 CLI 命令。

AI 测试

以下命令设计为可以逐步执行。在运行之前,请将所有占位符(例如 <namespace><blue-pod-0>)替换为实际值。

#检查项命令预期结果
1绿色集群已激活kubectl -n <namespace> get rabbitmqclusters <green-instance-name>PHASE: Active
2已导入定义kubectl exec -n <namespace> <green-pod-0> -- rabbitmqctl list_queues nameSame queues as blue
3Federation 插件已启用kubectl exec -n <namespace> <green-pod-0> -- rabbitmq-plugins list -erabbitmq_federation listed
4已设置 Federation 上游kubectl exec -n <namespace> <green-pod-0> -- rabbitmqctl list_parametersfederation-upstreamblue exists
5Federation 链路正在运行kubectl exec -n <namespace> <green-pod-0> -- rabbitmqctl eval 'rabbit_federation_status:status().'Status is running
6绿色集群上的消费者在接收消息kubectl exec -n <namespace> <green-pod-0> -- rabbitmqctl list_queues name messages consumersconsumers > 0
7蓝色队列正在清空kubectl exec -n <namespace> <blue-pod-0> -- rabbitmqctl list_queues name messagesMessage count decreasing
8蓝色队列为空Same as aboveAll queues show 0
9绿色集群上的生产者kubectl exec -n <namespace> <green-pod-0> -- rabbitmqctl list_queues name messagesMessages increasing
10Federation 已清理kubectl exec -n <namespace> <green-pod-0> -- rabbitmqctl list_parametersNo federation parameters

回滚

如果在迁移过程中遇到问题:

  1. 在迁移消费者之前:直接删除绿色集群即可。对现有服务没有影响。
  2. 在迁移消费者之后、迁移生产者之前:将消费者切回蓝色集群,并删除绿色集群。
  3. 在完全迁移之后:如果绿色集群出现问题,创建一个新的 3.12.x 实例,导入定义,然后切换回去。请注意,在切换后发送到绿色集群的消息,需要通过 shovel 或反向 Federation 迁回并清空。