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. Scrum Meeting 目录 && alpha 第一次Scrum Meeting博客

    是兄弟就来摸鱼小组 Scrum Meeting 博客汇总 一.Alpha阶段 标号 标题 1 [alpha]第一次Scrum Meeting(见本文) 二.Beta阶段 会议安排 时间 4月23日8时 ...

  2. 对DiscuzQ的一些使用见解

    之前因为体验了DiscuzQ,在几番纠结后,把博客换成了DiscuzQ(以下简称DZQ). 在一个月的使用中,发现这个程序对于个人来说,十分不友好. 于是今天又换回了Wordpress. 在这里说一下 ...

  3. input 的各种属性的验证 checkValidity兼容性

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  4. Thinkphp5 日期与时间戳相互转换

    日期转换为时间戳 $date="2013-10-01 12:23:14"; dump(strtotime($date)); //=>1380601394 时间戳 转换为日期 ...

  5. 缓冲区溢出分析第07课:MS06-040漏洞研究——静态分析

    前言 我在之前的课程中讨论过W32Dasm这款软件中的漏洞分析与利用的方法,由于使用该软件的人群毕竟是小众群体,因此该漏洞的危害相对来说还是比较小的.但是如果漏洞出现在Windows系统中,那么情况就 ...

  6. POJ2771最大独立集元素个数

    题意:       女生和男生之间只要满足四个条件中的一个,那么两个人就不会在一起!然后给出一些男生和女生,问最多多少人一起做活动彼此不会产生暧昧关系. 思路:       这样的问题还是比较裸的问法 ...

  7. 【python】Leetcode每日一题-删除排序链表中的重复元素2

    [python]Leetcode每日一题-删除排序链表中的重复元素2 [题目描述] 存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除链表中所有存在数字重复情况的节点,只保留原始链表 ...

  8. JUC 并发类概览

    JUC 并发类及并发相关类概览,持续补充... AQS 内部有两个队列,一个等待队列(前后节点),一个条件队列(后继节点),其实是通过链表方式实现: 等待队列是双向链表:条件队列是单向链表:条件队列如 ...

  9. python模块导入原理

    转自:http://blog.csdn.net/u012422440/article/details/41791433 今日在自学Python,借此机会,正好重新开始写博文,既可以巩固python的知 ...

  10. CRM是什么意思,有哪些作用?

    我们总会听到一些人提到CRM或CRM系统,但是通常不知道它的含义,所以今天小Z就来详细介绍一下CRM. GartnerGroup1993年首次提出了这一概念:所谓的客户关系管理就是为企业提供一个全面的 ...