1.消息的发送流程

一条消息从生产到被消费,将会经历3个阶段

  • 生产阶段,Producer 新建消息,然后通过网络将消息投递给MQ Broker
  • 存储阶段,消息将会存储在Broker端磁盘中
  • 消费阶段,Consumer将会从Broker拉取消息

    以上3个阶段,都有可能会丢失消息,只要找到这3个阶段丢失消息的原因,采取合理的办法进行避免,就可以彻底解决丢失消息问题。

2.生产阶段

Prodducer 通过网络发送消息给Broker,当Broker收到之后,将会返回确认响应信息给Producer,所以生产者只有接收到返回的确认响应,就代表消息在生产阶段未丢失

同步发送伪代码

DefaultMQProducer mqProducer=new DefaultMQProducer("test");
// 设置 nameSpace 地址
mqProducer.setNamesrvAddr("namesrvAddr");
mqProducer.start();
Message msg = new Message("test_topic" /* Topic */,
"Hello World".getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */
);
// 发送消息到一个Broker
try {
SendResult sendResult = mqProducer.send(msg);
} catch (RemotingException e) {
e.printStackTrace();
} catch (MQBrokerException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}

send 方法是同步操作,只要这个方法不抛出异常,就代表消息已经发送成功

消息发送成功仅代表消息已经到了Broker端,Broker在不同配置下,可能返回不同的状态

  • SendStatus.SEND_OK

    消息发送成功,消息发送成功,不意味着它是可靠的,要保证不会丢失任何信息,还应启用同步Master服务器或同步刷盘,即SYNC_MASTER或SYNC_FLUSH
  • SendStatus.FLUSH_DISK_TIMEOUT

    消息发送成功,但是服务器刷盘超时.消息进入到了broker的内存里,只有服务器戎机,消息才会丢.消息存储配置参数中可以配置刷盘方式和同步刷盘的时间长度,如果是同步刷盘,FlushDiskType=SYNC_FLUSH(默认是异步刷盘),当Broker服务器未在同步刷盘时间内(默认5秒)完成刷盘,则将返回该状态-刷盘超时
  • SendStatus.FLUSH_SLAVE_TIMEOUT

    消息发送成功,但是服务器同步到Slave超时,消息进入到了broker的内存里,只有broker戎机,消息才会丢。如果Broker角色是同步Master,及SYNC_MASTER(默认是异步Master及ASYNC_MASTER),并且从Broker未在同步刷盘时间内(5秒)内完成与从服务器的同步,就会返回数据同步Slave超时
  • SendStatus.SLAVE_NOT_AVAILABLE

    消息发送成功,Slave不可用,同步master,单没配置slave broker,会返回此状态

异步发送伪代码

DefaultMQProducer mqProducer = new DefaultMQProducer("test");
// 设置 nameSpace 地址
mqProducer.setNamesrvAddr("127.0.0.1:9876");
mqProducer.setRetryTimesWhenSendFailed(5);
mqProducer.start();
Message msg = new Message("test_topic" /* Topic */,
"Hello World".getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */
); try {
// 异步发送消息到,主线程不会被阻塞,立刻会返回
mqProducer.send(msg, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
// 消息发送成功,
} @Override
public void onException(Throwable e) {
// 消息发送失败,可以持久化这条数据,后续进行补偿处理
}
});
} catch (RemotingException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}

异步发送,要重写回调方法,在回调方法中检查发送结果

不管同步还是异步,都会碰到网络问题导致发送失败的请求,针对这种情况,我们可以设置合理的重试次数,当出现网络问题,可以自动重试,设置方式如下

// 同步发送消息重试次数,默认为 2
mqProducer.setRetryTimesWhenSendFailed(3);
// 异步发送消息重试次数,默认为 2
mqProducer.setRetryTimesWhenSendAsyncFailed(3);

3.存储阶段

消息到了Broker端,将会优先保存到内存里,然后立刻返回确认响应ack给生产者。随后Broker 定期批量的将一组消息从内存中异步刷到磁盘中

定期异步刷数据到盘的操作,减少了IO次数,可以有更好的性能,但是如果发生几起掉电,戎机的情况,消息还未及时刷到磁盘,就会出现丢失消息的情况。

如果要保证Broker端不丢消息,需要将消息的保存机制改为同步刷盘方式,来一个消息,刷一下到磁盘中,再返回响应。

master配置修改

flushDiskType = SYNC_FLUSH

当Broker未在同步时间内(默认5秒)完成刷盘,将会返回SendStatus.FLUSH_DISK_TIMEOUT状态给生产者

高可靠

broker通常采用集群部署,一主多从架构,为了保证消息不丢,消息还会复制到slave节点

默认情况下,消息写入master成功,就可以返回确认响应ack给生产者,接着消息异步复制到slave节点

此时若Master突然戎机不可恢复,那么还未恢复到slave的消息将会丢失

为了进一步提高消息可靠性,可以采用同步的复制方式,master节点将会同步等待slave节点复制完成,才会返回确认响应。

异步复制与同步复制的区别如下:

Broker master节点同步复制配置如下

brokerRole = SYNC_MASTER

如果slave 节点未在指定时间内同步返回响应,生产者将会受到SendStatus.FLUSH_SLAVE_TIMEOUT返回状态


如果 要严格保证消息不丢,broker需要如下配置:

## master 节点配置
flushDiskType = SYNC_FLUSH
brokerRole = SYNC_MASTER ## slave 节点配置
brokerRole = slave
flushDiskType = SYNC_FLUSH

生产者要配合,判断返回状态是否SendStatus.SEND_OK,若是其他状态,需要考虑补偿重试。上述配置会提高消息的可靠性,但是会降低性能,生产实践中需要综合选择。不是完全固化的配置

4.消费阶段

消费者从broker拉取消息,然后执行相应的业务逻辑,一旦执行成功,将会返回ConsumeConcurrentlyStatus.CONSUME_SUCCESS状态给Broker

如果Broker 未收到消息确认响应或收到其他状态,消费者下次还会再次拉取到该条消息,进行重试。

此种方式有效避免了消费者消费过程中发生异常,消息在网络传输中丢失的情况

消费伪代码

// 实例化消费者
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("test_consumer"); // 设置NameServer的地址
consumer.setNamesrvAddr("namesrvAddr"); // 订阅一个或者多个Topic,以及Tag来过滤需要消费的消息
consumer.subscribe("test_topic", "*");
// 注册回调实现类来处理从broker拉取回来的消息
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
// 执行业务逻辑
// 标记该消息已经被成功消费
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
// 启动消费者实例
consumer.start();

以上消费消息过程的,我们需要注意返回消息状态。只有当业务逻辑真正执行成功,我们才能返回 ConsumeConcurrentlyStatus.CONSUME_SUCCESS。否则我们需要返回 ConsumeConcurrentlyStatus.RECONSUME_LATER,稍后再重试。

如何保证mq不丢消息的更多相关文章

  1. 面试官再问我如何保证 RocketMQ 不丢失消息,这回我笑了!

    最近看了 @JavaGuide 发布的一篇『面试官问我如何保证Kafka不丢失消息?我哭了!』,这篇文章承接这个主题,来聊聊如何保证 RocketMQ 不丢失消息. 0x00. 消息的发送流程 一条消 ...

  2. 23 | MySQL是怎么保证数据不丢的?

    今天这篇文章,我会继续和你介绍在业务高峰期临时提升性能的方法.从文章标题“MySQL是怎么保证数据不丢的?”,你就可以看出来,今天我和你介绍的方法,跟数据的可靠性有关. 在专栏前面文章和答疑篇中,我都 ...

  3. kafka什么时候会丢消息(转)

    因为在具体开发中某些环节考虑使用kafka却担心有消息丢失的风险,本周结合项目对kafka的消息可靠性做了一下调研和总结: 首先明确一下丢消息的定义.kafka集群中的部分或全部broker挂了,导致 ...

  4. MQ如何解决消息的顺序问题和消息的重复问题?

    一.摘要 分布式消息系统作为实现分布式系统可扩展.可伸缩性的关键组件,需要具有高吞吐量.高可用等特点.而谈到消息系统的设计,就回避不了两个问题: 1.消息的顺序问题 2.消息的重复问题 二.关键特性以 ...

  5. .net core 和 WPF 开发升讯威在线客服系统:怎样实现拔网线也不丢消息的高可靠通信(附视频)

    本系列文章详细介绍使用 .net core 和 WPF 开发 升讯威在线客服与营销系统 的过程.本产品已经成熟稳定并投入商用. 在线演示环境:https://kf.shengxunwei.com 注意 ...

  6. IBM MQ消息中间件jms消息中RHF2消息头的处理

    公司的技术平台在和某券商对接IBM MQ消息中间件时,发送到MQ中的消息多出了消息头信息:RHF2,造成消息的接收处理不正常.在此记录此问题的处理方式. 在IBM MQ中提供了一个参数 targetC ...

  7. MQ发送的消息都到了死信队列中了

    MQ在发送消息的时候,设置的过期时间太短.(昨天项目上线遇到了,开发中也遇到一次.)谨记!!!

  8. 记一次mq无法正常生产消息的事故排查过程

    早上上班后得知,服务费未同步到代理商系统.查看draft_server系统生产环境的log,显示在往RabbitMQ推数据时出现异常:no route to host. 2019-07-29 01:3 ...

  9. RabbitMQ消息丢失问题和保证消息可靠性-消费端不丢消息和HA(二)

    继续上篇文章解决RabbitMQ消息丢失问题和保证消息可靠性(一) 未完成部分,我们聊聊MQ Server端的高可用和消费端如何保证消息不丢的问题? 回归上篇的内容,我们知道消息从生产端到服务端,为了 ...

随机推荐

  1. 1149 Dangerous Goods Packaging

    When shipping goods with containers, we have to be careful not to pack some incompatible goods into ...

  2. system分区解锁

    前言 获取root权限,解锁system 步骤 手机设置 设置--更多设置--开发者选项--USB调试给打开 电脑操作 打开cmd adb devices 执行命令 adb root &&am ...

  3. php变量的命名规则

    php变量的命名规则 1.变量以美元符号$开头.如$name,$age: 2.美元符号$后面的第一个字符不可以是数字: 3.除了下划线_外,变量不允许出现任何空格或者标点符号: 4.PHP变量名是区分 ...

  4. 最新版Theos.2016.08的安装方法

    http://bbs.pediy.com/showthread.php?t=212425 标题: [翻译]手把手安装最新版Theos.2016.08作者: roysue时间: 2016-08-26,1 ...

  5. Python中hashlib模块的使用

    hashlib是 python 下一款与加密相关的库包,提供摘要算法:md5.sha1.sha224.sha256.sha384.sha512.blake2b.blake2s.sha3_224.sha ...

  6. android Javah生成JNI头文件

    项目要用到c语言库,因此来学习下jni 首先是在cmd中使用javah,出现了javah不是内部或外部命令的错误提示,javah是jdk自带的工具,提示说明在系统环境变量中没有jdk的路径,或者配置错 ...

  7. [CTF]猪圈密码

    [CTF]猪圈密码 -------------------- 百度百科 本词条由"科普中国"百科科学词条编写与应用工作项目 审核 . https://baike.baidu.com ...

  8. docker文件系统分层存储原理

    一,前言 众所周知,docker镜像技术的基础是联合文件系统(UnionFS),其文件系统是分层的,那它的分层机制是什么样的呢?共分为几种层呢?又是怎么工作的呢? 目前docker支持的联合文件系统有 ...

  9. 前端小白的学习之路html与css的较量【一】

    html和css的较量 web结构的组成 html标签规则 快速生成一个html html的基本结构 标签的关系 标签 标题标签 段落 图片 超链接 a 属性 a标签里面的值 字符实体 新增的标签 1 ...

  10. 【js】Leetcode每日一题-叶子相似的树

    [js]Leetcode每日一题-叶子相似的树 [题目描述] 请考虑一棵二叉树上所有的叶子,这些叶子的值按从左到右的顺序排列形成一个 叶值序列 . 举个例子,如上图所示,给定一棵叶值序列为 (6, 7 ...