专栏首页程序员升级之路RabbitMQ跨机房迁移数据零丢失

RabbitMQ跨机房迁移数据零丢失

一、背景介绍

公司以前大部分服务在私有云上,因使用有一段时间了,机器比较老化再加上运维成本高,计划将整个机房上云,因负责中间件一块,所以最近将RabbitMQ顺利地迁移到云上。

先说下大概部署结构,为 保证高可用,在私有云上部署了3台Broker,应用在配置文件中直接配置3个IP,每次请求时由客户端随机选择1台。

本次迁移的目标是:

1、零数据丢失,但不保证消息不重复消费;

2、不出现整个MQ集群长时间(2分钟以上)不可用;

二、方案分析

关于数据丢失,我们先要知道RabbitMQ中有哪些数据:

Exchange、Queue、Message。

关于Exchange和Queue,可以设置在不存在的时候创建,但这样难以管控,所以一般我们都是在后台由管理员创建Exchange和Queue,并设置好相应属性,一般来说都要设置为持久化,即durable为true,这样保证在Broker重启时Exchange和Queue还存在。

Message的持久化则要在发送的时候设置相应的参数,如果用的amqp-client这个包,则代码如下:

  channel.basicPublish(exchange, routingKey, basicProperties, payload);

其中为basicProperties为消息属性,类型为AMQP.BasicProperties

public static class BasicProperties extends com.rabbitmq.client.impl.AMQBasicProperties {
        private String contentType;
        private String contentEncoding;
        private Map<String,Object> headers;
        private Integer deliveryMode;
        private Integer priority;
        private String correlationId;
        private String replyTo;
        private String expiration;
        private String messageId;
        private Date timestamp;
        private String type;
        private String userId;
        private String appId;
        private String clusterId;

关注deliveryMode属性,要设为2消息才会持久化。

再来分析下有哪些场景下可能导致数据丢失:

1、单机宕机无法启动

假设机群有3台Broker:A、B、C,发送消息的机制如下:

如果当前请求落到A上,则消息中会保存在A这个节点上,持久化也只持久化到这台机上。

如果消息还没有被消费,这个时候A宕机,则这条消息就丢了。

针对这种情况,官方推荐用镜像队列的方案,这时消息发送过程如下:

消息先发送到队列所在Master机器A,然后A将消息同步到所有其它机器上。

这时即使A宕机了,整个集群会做漂移,将这个列列的Master漂移到另外1台机器上,因为在发送的时候消息已经同步到所有其它机器上了,因此消息不会丢失,但有可能重复消费,这就需要业务做幂等处理。

镜像队列添加命令如下:

Virtual host : "/oneplus"
Name : "all_ha"
Pattern : "^"
Apply to : "Queues"
Priority : 0
ha-mode : all
ha-sync-mode : automatic

2、脑裂

这个我们在生产上碰到过,可以加上以下配置避免:

{cluster_partition_handling, pause_minority}

另外在迁移过程中注意几点:

1)、尽量保证集群总机器数为奇数;

2)、尽量减少跨机房集群存在的时间;

那么除以做为以上我们是不是可以高枕无忧地说整个迁移万无一失了呢,上面只是讲了技术的原因,我们还要来通过其它方面来保障过程的稳定性:

1、测试

搭建整套的环境测试,以验证整个方案的有效性。

2、做好故障预案

A、备份好元数据

可以在RabbitMQ管理界面后台操作。

B、核心流程必须有数据核对方案

因为我们是电商,所以要保证整个交流主流程上的MQ消息不能丢失,所以需要有一套数据核对及补偿的方案,这个就不在这里详述了。

三、迁移过程

最后说下我们整个迁移的过程

1、第一步就是当前状态

2、在新机器房添加4台Broker

在每台机器上执行命令如下:

rabbitmqctl stop_app
rabbitmqctl join_cluster rabbit@${server1}
rabbitmqctl start_app

3、下线新、老机房各一台Broker,保证总数仍为奇数

先在要下线的机器上执行命令:

rabbitmqctl stop_app

然后在存活的节点上执行命令

rabbitmqctl forget_cluster_node rabbit@${server1}

4、最后下掉老机房剩下机器

命令同上

最后总结下,我们从以下几方面保证迁移过程的稳定性:

1、配置好各项参数,保证MQ内部各数据尽量不丢失

主要做了以下几方面的工作:配置好镜像队列、防止脑裂;

2、在测试环境做好充分的验证;

3、保证主流程消息有核对及补偿方案。

本文分享自微信公众号 - 程序员升级之路(gh_1fab42db66cb),作者:刘江华

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-06-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 直播评论系统分析设计

    直播评论系统是电商系统一个常用的功能,即在发布新品的时候,为了吸引用户参与和营造互动气氛,让参与的每个人都可以发消息,发完后每个人都可以即时看到新消息,原型和 ...

    心平气和
  • 也谈限流

    限流的技术现在用的比较普遍了,网上一搜应该有大把的文章,为什么还来凑这个热闹呢,因为最近我们公司也在做限流,限流参考是以并发请求数作为限流参考的,即来一...

    心平气和
  • 接口403问题没这么容易解决

    最近一同事反馈在后台保存某业务数据时一直报403,该数据由运营人员在后台录入,然后向后端发送POST请求保存数据;现象是如果内容过长如几十K则报403,如果只输...

    心平气和
  • 函数重构之道

    以下代码做了好几件事情。它创建缓冲区、获取页面、搜索继承下来的页面、渲染路径、添加神秘的字符串、生产HTML等等。

    栋先生
  • SpringBoot基础篇配置信息之配置刷新

    配置的刷新,从第一篇就提出了这个问题,但是一直都没有说到,那么配置加载完毕之后能否在主动刷新呢?

    一灰灰blog
  • ApiBoot 2.0.7.RELEASE 版本发布

    ApiBoot是一款基于SpringBoot1.x,SpringBoot2.x的接口服务集成基础框架,内部提供了框架的封装集成、使用扩展、自动化配置等,让接口开...

    恒宇少年
  • Spring Boot 返回 JSON 数据,一分钟搞定!

    除了 Spring Boot 必须自带的 parent 依赖外,仅仅只需要加入这个 spring-boot-starter-web 包即可,它会自动包含所有 J...

    Java技术栈
  • 使用桥接模式来显示下单结果 顶

    在用工厂方法模式来下不同订单 中我们看到,我们只简单显示来一个“下单成功”,但实际上我们需要给用户返回到结果可能多种多样。

    算法之名
  • Android使用注解代替枚举节省系统内存开销的方法

    Java5以后开始支持枚举类型,枚举类型使用起来非常方便,其重要的作用是作为类型安全使用的。如果在不考虑系统内存开销的情况下大量的使用枚举也不会有什么问题。但是...

    砸漏
  • springBoot整合发送邮件功能

    本文将介绍spring官方提供的集成了邮件服务的JavaMailSenderImpl,开箱即用,十分方便。

    贪挽懒月

扫码关注云+社区

领取腾讯云代金券