• 消息队列(二)


    消息队列发送消息

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

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

    同步可靠发送

    原理:同步可靠发送是指发送方发出数据后,会等待直到接收方发回响应后才发出下一条消息。如下所示(图来自消息队列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)

    消息传递
    4. MQ-Server将消息发送给MQ-Client(MQ-Server回调ReceiveMsgCallback接口)
    5. MQ-Client发送应答ACK给MQ-Server(业务方调用sendAck())
    6. MQ-Server接收到ACK,将之前落地的消息删除

    由上我们可以看出消息发送和消息传递过程中都可能发送消息丢失,所以我们为了保证消息的可靠性,MQ需要进行消息重传和超时

    消息发送的超时和重传
    在消息发送过程中1、2、3可能出现消息丢失或者超时,由于MQ-Client没有收到回调消息,所以MQ-Client会在time时间内重发消息直到收到回调消息。需要注意的是,这里可能造成MQ-Server收到同一消息的多次重发,也就是造成了消息重复。

    消息传递的超时和重传
    在消息传递过程中的4、5、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有时间限制,所以没有列出来)

  • 相关阅读:
    mysql的启动出现错误 install/remove denied错误操作
    mybatis的开发方式
    mysql绿色版安装出现1067的错误原因
    线程池中对于异常的处理操作
    spring中的aync注解的使用与事务操作
    互联网金融产品经理 修炼之道
    几句牢骚
    做自己
    自动加载与访问权限
    mvc模式实现
  • 原文地址:https://www.cnblogs.com/maying3010/p/8512528.html
Copyright © 2020-2023  润新知