消息队列(二)

消息队列发送消息

MQ发送消息有三种实现方式html

  • 同步可靠发送
  • 异步可靠发送
  • 单向不可靠发送

同步可靠发送

原理:同步可靠发送是指发送方发出数据后,会等待直到接收方发回响应后才发出下一条消息。以下所示(图来自消息队列MQ新增3把武器)设计模式

图来自网络

应用场景:此种方式应用场景很是普遍,例如重要通知邮件、报名短信通知、营销短信系统等。服务器

异步可靠发送

原理:异步可靠发送是指发送方发出数据后,不等待接受方发回响应,接着发送下一个消息。其可靠保障主要是须要发送方发送异步回调接口(SendCallback),在服务器接受到消息后回调该接口发送接收响应。以下所示(图来自消息队列MQ新增3把武器)
图来自网络微信

应用场景:异步可靠发送通常用于链路耗时较长,对RT响应时间较为敏感的业务场景,例如用户视频上传后通知启动转码服务,转码完成后通知推送转码结果等。网络

单向不可靠发送

原理:单向不可靠发送特色时只负责发送消息,不等待服务器回应其也没有回调函数的触发,即只发送消息不等待应答。该方式发送消息过程耗时很是短。以下所示(图来自消息队列MQ新增3把武器)
图来自网络架构

应用场景:适用于某些耗时很是短且对可靠性要求不高,但对可靠性要求并不高的场景,例如日志收集。异步

三种方式的特色和区别以下:函数

方式 发送TPS 发送结果反馈 可靠性
同步可靠发送 较快 不丢失消息
异步可靠发送 不丢失消息
单向不可靠发送 最快 可能丢失消息

消息队列接收消息

MQ接收消息也有同步和异步的区分,这里主要讲异步的方式,其中异步主要有下面两种方式:线程

  • Push Message(推消息)
  • Pull Message(拉消息)

这里不论是推仍是拉,都是异步状况下。该状况下,MQ服务器异步发送消息给客户端,客户端在接收消息后会发送ACK消息给MQ服务器表示已经接收到ACK消息后删除消息,这样保证消息的可靠到达。设计

mark

推、拉消息

推消息(Push)主要指MQ-Server主动把消息推送给消费者,拉消息(Pull)主要指消费者主动向MQ-Server拉消息。Push、Pull主要是有如下优缺点:

1. 慢消费

慢消费指的是消费者消费消息的速度达不到生产者生成消息的速度。慢消费会形成的MQ-Server消息积压,在Push模型下MQ-Server会一直不断的向消费者发送消息,形成网络积压。而Pull模型下因为是消费者主动向MQ-Server拉消息,因此不会形成网络积压。

2. 消息延迟与忙等
消息延迟和忙等主要是Pull模型形成的问题。Push模型主动权在MQ-Server这里因此不会形成上诉问题。而因为Pull模型主动权在消费者,消费者会主动向MQ-Server拉消息,因此出现消费者何时去Pull消息,因此会操做消息延迟。在RocketMQ中,其使用一种长轮询的作法去Pull消息。基本思路是:消费者尝试拉消息,若是拉取失败则会把该链接wait,直到有新消息来而后notify返回新消息。

消息队列架构

下图是MQ的核心架构图(图来自微信公众号 <架构师之路> ),注:都是异步可靠方式

图来自微信公众号

消息队列核心架构分为3块

  1. 发送方:红色区域,其由MQ-Client和业务调用模块构成
  2. MQ服务器:蓝色区域,其指的是Broker(消息中间件代理)
  3. 接收方:黄色区域,其由MQ-Client和业务调用模块构成

发送方由业务调用模块和MQ-Client-Sender组成,后者向前者提供两个核心API:

  • sendMsg(byte[] msg)
  • sendCallback(Callback callback)

接受方由业务调用模块和MQ-Client-Receiver组成,后者向前者提供两个核心API:

  • ReceiveMsgCallback(byte[] bytes)
  • sendAck()

这里有点像设计模式中的事件驱动模式,当有MQ-Client-Sender、MQ-Client-Receiver时就至关于向MQ-Server注册这两个事件。当MQ-Server接收到消息时回调MQ-Client-Sender事件接口以告知MQ-Client-Sender已经接收到该消息,当MQ-Server发现符合MQ-Client-Receiver的消息时,就回调MQ-Client-Receiver事件接口以发送消息。

消息队列消息可靠性的保证

MQ须要接收生产者生成的消息并把消息传递给消费者进行消息消费,因此MQ须要保证消息发送和消息传递的可靠性。注:图来自微信公众号 <架构师之路>

图来自微信公众号<架构师之路

消息发送

  1. MQ-Client将消息发送给MQ-Server(业务方调用sendMsg())
  2. MQ-Server将消息落地(就是存放消息),落地后即为发送成功
  3. MQ-Server发送应答给MQ-Client(MQ-Server回调Callback)

消息传递

  1. MQ-Server将消息发送给MQ-Client(MQ-Server回调ReceiveMsgCallback接口)
  2. MQ-Client发送应答ACK给MQ-Server(业务方调用sendAck())
  3. MQ-Server接收到ACK,将以前落地的消息删除

由上咱们能够看出消息发送和消息传递过程当中均可能发送消息丢失,因此咱们为了保证消息的可靠性,MQ须要进行消息重传和超时

消息发送的超时和重传
在消息发送过程当中一、二、3可能出现消息丢失或者超时,因为MQ-Client没有收到回调消息,因此MQ-Client会在time时间内重发消息直到收到回调消息。须要注意的是,这里可能形成MQ-Server收到同一消息的屡次重发,也就是形成了消息重复。

消息传递的超时和重传
在消息传递过程当中的四、五、6可能出现消息丢失或者超时,因为MQ-Server没有收到Ack消息因此会形成MQ-Server重发消息,也就是形成了消息重复。

也就是说:因为要保证消息的可靠性会致使消息重复

消息去重

由上面咱们可知在保证消息的可靠性上回致使消息的重复,而且多条消息body可能相同,因此须要咱们解决下面两种问题:

  • 避免消息重复消费
  • 避免多条相同body的消息被过滤

本身在网络上看了许多的方案,发现消息去重通常由业务端本身去解决,主要保证消费者消费消息的幂等性

消费消息的幂等性

咱们能够下生产者生成消息时在消息体中插入去重key,在消费者消费消息时,经过去重key保证相同消息不会被重复消费而且保证相同body的消息不会被过滤。其中去重key能够由<生产者IP+线程ID+时间戳+时间内递归值>组成惟一值。具体可见:腾讯云关于消费去重文章

Reference

http://jm.taobao.org/2016/07/21/3-ways-to-send-message
https://tech.meituan.com/mq-design.html
https://cloud.tencent.com/document/product/406/4791 架构师之路工做号《消息总线可否实现消息必达?》(因为微信公众号文章URL有时间限制,因此没有列出来)

相关文章
相关标签/搜索