MQ可以用在哪些地方,解决什么问题?

2023-11-05

MQ
kafka是以吞吐量高而闻名,不过其数据稳定性一般,而且无法保证消息有序性。

阿里巴巴的RocketMQ基于Kafka的原理,利用Java代码打造,弥补了Kafka的缺点,继承了其高吞吐的优势,其客户端目前以Java为主。

RabbitMQ基于面向并发的语言Erlang开发,吞吐量不如Kafka,但是消息可靠性较好。也能有效的保证消息的有序性。因为Erlang的原因,集群搭建比较方便。支持多种协议,并且有各种语言的客户端,比较灵活。

相关资料:

这个问题其实时问3种MQ的差别,先看一张图:

在这里插入图片描述

ActiveMQ现在已经很少使用,社区不太活跃,放弃。

RabbitMQ并发能力强、消息延时低、高可用、管理界面丰富,并且最重要的是:社区非常活跃,出现BUG都能及时解决。

Kafka和RocketMQ的特点都是高吞吐量,但是kafka消息可靠性比较一般,而且消息不保证有序性。RocketMQ弥补了Kafka的缺点,不过是阿里开源,社区不太活跃,文档也不够丰富。

RabbitMQ可以 干嘛

1)解耦合

例如系统A执行完业务,系统B需要得到系统A的业务结果,此时可以系统A中调用系统B(系统A中耦合了系统B的业务)。

此时如果系统C、系统D都有类似需求,那么系统A的业务逻辑还要继续修改,违反了开闭原则。

在这里插入图片描述

此时,可以利用MQ来解耦,让商品微服务发送消息通知,而相关的其它系统监听MQ即可:
在这里插入图片描述

2)流量削峰

数据库的并发能力有限,往往称为业务执行的性能瓶颈。

例如我们的服务只能支持500的并发,然而又每秒1000甚至更高的服务流量涌入,服务肯定会崩溃的。

在这里插入图片描述

此时,利用MQ来作为缓冲,就像大坝一样,高并发流量涌入,先放到MQ中缓存起来,后续系统再慢慢取出并处理即可:

在这里插入图片描述

3)异步调用

如果一个业务执行中,需要调用多个其它服务,业务链路很长,同步调用的用时就时多个服务执行的总耗时,如图:

在这里插入图片描述

但是,我们如果再B系统执行完成后,利用MQ通知系统C和系统D去完成,直接返回结果给用户,就可以减少业务耗时。这样就把同步阻塞调用,变成了异步调用:

在这里插入图片描述

4)延迟队列

例如定时清理订单的需求,我们在下单完成后,如果用户超过半小时未支付,需要关闭订单。此时我们就需要发送延迟消息,即:发送消息半小时后,消费者才能收到消息,这就是延迟队列。

RabbitMQ的死信队列可以实现延迟队列效果,如图:

在这里插入图片描述

RocketMQ也可以实现延迟队列,但是RocketMQ的延迟队列的时间只能是固定时间间隔。

如何保证RabbitMQ的高可用

RabbitMQ

RabbitMQ底层基于Erlang语言,对分布式支持较好。并且官方也给出了搭建镜像机器的方式,可以把队列及其中的数据同步到镜像节点中,当队列所在节点故障时,镜像队列可以继续提供服务。

另外,MQ数据可以持久化,当节点恢复时,可以恢复数据。

RocketMQ

RocketMQ中的核心组件是NameServer和Broker,这两部分都可以建立主从集群,保证高可用:在这里插入图片描述

如何保证RabbitMQ的消息可靠性,防止消息丢失?

我们针对MQ消息丢失的几种不同情况,采用不同的应对方案:

  • 生产者发送消息时可能因为网络问题导致消息丢失:
    • 利用RabbitMQ提供的publisher confirm机制,参考文档
      • 生产者发送消息后,可以编写成功回调函数或失败超时回调函数
      • RabbitMQ接收消息成功并持久化会调用成功回调函数,通知消息的发送者
      • RabbitMQ接收消息时出现异常会调用失败回调函数,通知消息的发送者
      • 消息超时未发送成功也会调用失败回调函数
  • MQ宕机导致丢失消息:
    • 消息持久化,RabbitMQ会将消息持久化到磁盘,宕机重启可以恢复消息
    • 镜像集群,主从备份,避免引宕机导致消息丢失
  • 消费者丢失消息:避免引消费者异常或宕机导致消息丢失
    • 消费者的确认机制,在处理消息结束后,手动Acknowledge回执给MQ
    • MQ未接受到Acknowledge会认为消费失败,消息会保留在MQ

rabbitmq中消息消费后自动删除,不会永久保留,无法实现消息回溯。

如何防止MQ消息的重复消费?

消息重复消费产生的原因:

  • 因为网络故障,导致生产者确认机制失败,生产者重发消息
  • 因为网络故障,导致生产者确认机制失败,MQ重新投递消息

解决思路:业务处理时,保证处理消息接口的幂等性。

  • 能根据具体的业务或状态来确定的,在消费端通过业务判断是否执行过,例如新增订单,看看订单ID是否已经存在
  • 对于无法通过业务判断的,我们可以为每一条消息设置全局唯一id,保存到数据库消息表。消息处理前对ID进行判断即可

如何解决MQ的消息堆积问题?

RabbitMQ支持多消费者绑定同一队列,消息Broker会把消息轮询的发送给每一个消费者。通过同一个队列多消费者监听,实现消息的争抢,加快消息消费速度。

RabbitMQ也可以做集群,集群数据会分片效果,从而能堆积更多消息。

备选方案:也可以给单个消费者接收消息后放入队列,交给线程池去处理。

如何保证MQ消息的有序性?

某个业务发出了3条消息,要求这3条消息按照发送时的顺序执行。

  • 业务对并发要求不高:
    • 保证消息发送时有序同步发送
    • 保证消息发送被同一个队列接收,MQ本身是先进先出,保证消息有序
    • 保证一个队列只有一个消费者,避免多个消费者争抢导致顺序混乱
  • 业务同时对并发要求较高:
    • 满足上述第一个场景的条件
    • 可以有多个队列
    • 有时序要求的一组消息,通过hash方式分派到一个固定队列

如何利用RabbitMQ实现延迟队列

RabbitMQ中有一个死信队列设定:我们可以给一个队列设置过期时间,或者发送消息时给消息设置过期时间。过期的消息称为死信,队列会把死信转发给提前设置的死信交换机,而与死信交换机绑定的队列就可以拿到这些消息。

因为发送消息超过一定时间(过期)后,才会被队列拿到,这样就实现了延迟队列效果。

实现起来非常简单,不过也有一些缺陷:

  • 如果延迟消息过多,可能导致MQ的消息堆积过多
  • MQ消息无法删除,因此不能撤销延迟消息。

如果对上述问题有要求,可以利用Redis来实现延迟队列。

相关资料:

参考官方网站:https://www.rabbitmq.com/dlx.html

首先来看死信的概念。

死信

死信的英文是(Dead Letter),满足下列条件的消息被称为死信:

  • 消费者使用basic.reject或 basic.nack声明消费失败,并且消息的requeue参数设置为false。意思就是这个消息没有消费者需要了。
  • 消息是一个过期消息(TTL到期),到期可以是消息本身超时或者队列的TTL超时
  • 消息的长度超过了其被投递的队列最大限制

要实现延迟队列,我们肯定需要人为控制一个消息变为死信,因此我们一般采用上述的第二种方式:让一个消息在一段时间后过期,这种过期可以通过两种策略实现:

  • 队列TTL:通过x-message-ttl属性给消息所在队列设置TTL(Time To Live),当队列中的消息存在时间超过TTL后就自动成为死信
  • 消息TTL:消息的发送者在发送消息时,设置消息TTL属性。消息到达队列,TTL到期后成为死信、
  • 如果一个消息具有TTL,同时所在队列也具备TTL,时间长度较小的会生效

由上面的概念可以知道,一个消息是不是死信,最终是由消息所在的队列来判断和处理的。当一个消息被判定为死信,它所在的队列会做怎样的处理呢?

队列会把死信交给提前指定的死信交换机(Dead Letter Exchange)

如图:
在这里插入图片描述

死信交换机Dead Letter Exchanges

**死信交换机(Dead Letter Exchange)**其实就是一个普通交换机,也具备以前学习的交换机的所有特征,例如可以设置交换机类型为:topic、direct等。它负责把消息根据routing key转发给绑定的队列。

那什么样的交换机才可以叫死信交换机?需要队列在声明的时候,通过x-dead-letter-exchange属性指定一个交换机,被指定的交换机就是死信交换机(Dead Letter Exchange)。同时队列还可以指定一个x-dead-letter-routing-key(死信路由)作为死信的routing_key,死信交换机转发消息时会根据这个routing_key来转发消息。

死信交换机接收到消息以后,会根据消息的routing_key再次转发消息到绑定的队列,如果队列绑定到死信交换机时,会根据队列指定的x-dead-letter-routing-key来转发,如果队列没有绑定,则会根据消息来源时指定的routing_key来转发。

例如:现在publisher发送消息时指定routing_keyfoo,队列绑定死信交换机时指定了死信路由为:bar,则死信交换机转发时,会使用bar作为routing_key,如图:

在这里插入图片描述

现在publisher发送消息时指定routing_keyfoo,队列绑定死信交换机时没有指定**死信路由,则死信交换机转发时,会使用foo作为routing_key,如图:

在这里插入图片描述

现在,如果我们发送一个routingKey为foo的消息到达设置了过期时间为30秒的队列(图中的MessageQueue),30秒后消息过期,就会转发到死信交换机,然后就会发送到Queue1这个队列,我们的任务执行者监听Queue1,即可实现延迟队列了。

示例

接下来,我们通过示例来展示下死信队列,如图:
在这里插入图片描述

1)创建交换机

打开RabbitMQ的管理界面,然后先创建两个交换机:

  • normal.topic:一个普通的topic类型的交换机
  • dead.topic:一个普通topic类型的交换机,但是作为死信交换机来用
    在这里插入图片描述
    在这里插入图片描述

2)创建队列

然后创建两个队列:

  • dead.order.queue:死信队列,设置过期时间为20秒,
    • normal.topic交换机绑定,接收消息,routing_key为 order.evict
    • 指定x-dead-letter-exchangedead.topic这个死信交换机
    • 指定x-message-ttl设置消息过期时间
  • evict.order.queue:普通任务队列,接收死信交换机转发过来的消息,将来推送给消费者
    • dead.topic交换机绑定,接收消息,routing_key为 order.evict

死信队列:在这里插入图片描述
普通任务队列:在这里插入图片描述
最终:在这里插入图片描述

3)绑定普通队列与交换机

进入交换机界面,点击要绑定的交换机,例如:normal.topic在这里插入图片描述
在点开的界面填写要绑定的队列及routing_key:在这里插入图片描述
然后还要绑定evict.order.queuedead.topic这个交换机:在这里插入图片描述

4)测试发送消息

现在,向normal.topic交换机发送消息,指定routing_key为:order.evict在这里插入图片描述
可以看到dead.order.queue中已经有消息了:在这里插入图片描述
然后等待20秒后,看到消息到了evict.order.queue在这里插入图片描述

优缺点

RabbitMQ实现延迟队列的优缺点:

优点:

  • 实现简单
  • 可持久化
  • 高可用集群
  • 性能强
  • 实时性好

缺点:

  • 无法删除消息
  • 如果是时间跨度非常大并且频率高的任务,不太适合
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MQ可以用在哪些地方,解决什么问题? 的相关文章

随机推荐

  • 排序——冒泡排序(Bubble sort)

    定义 冒泡排序是一种较简单的排序算法 它重复地走访过要排序的元素列 依次比较两个相邻的元素 如果顺序 如从大到小 首字母从Z到A 错误就把他们交换过来 走访元素的工作是重复地进行直到没有相邻元素需要交换 也就是说该元素列已经排序完成 这个算
  • 黑客/网络安全【零基础自学】

    一 为什么选择网络安全 这几年随着我国 国家网络空间安全战略 网络安全法 网络安全等级保护2 0 等一系列政策 法规 标准的持续落地 网络安全行业地位 薪资随之水涨船高 未来3 5年 是安全行业的黄金发展期 提前踏入行业 能享受行业发展红利
  • 如何建设一个安全运营中心(SOC)?

    然信息安全管理问题主要是个从上而下的问题 不能指望通过某一种工具来解决 但良好的安全技术基础架构能有效的推动和保障信息安全管理 随着国内行业IT应用度和信息安全管理水平的不断提高 企业对于安全管理的配套设施如安全运营中心 SOC 的要求也将
  • wifi协议_图解 802.11wifi协议

    微信公众号 卢同学关注可了解更多 若有问题或建议 请与本人联系或者公众号留言 如果你觉得此文对你有帮助 欢迎赞赏 目录 凡事若能综观形势 通常有助于细节的进一步探究 从OSI七层模型来看 802规范的重心放在OSI模型最下面的两层 即数据链
  • Python爬虫入门7:HTML报文解析获取网页基本信息

    前往老猿Python博客 https blog csdn net LaoYuanPython 一 引言 BeautifulSoup是三方模块bs4中提供的进行HTML解析的类 可以认为是一个HTML解析工具箱 对HTML报文中的标签具有比较
  • wrieshark 抓包图解 MSDU AMSDU MPDU AMPDU 的区别

    区分这几种帧格式明确 802 3 和 802 11 两种帧格式即可 MSDU 首先 MSDU 是802 3的帧格式 从以太口发出去的帧都是MSDU格式的 A MSDU AMSDU 是把几个MSDU 聚合在一起并从以太网口发出去的帧 MPDU
  • 性能测试流程

    目 录 一 文档介绍 3 1 1文档目的 3 1 2适用对象 3 二 性能测试简介 3 2 1 性能测试概念 3 2 2 常用性能指标 4 2 3常用性能测试工具 5 三 性能测试流程 6 3 1 性能测试流程图 6 3 2 性能测试流程详
  • APScheduler 源码阅读(二) job

    趁热打铁 学习一下 APScheduler 的 python 的源码 很好奇任务调度控制的实现 分析源码主要还是针对 APScheduler 下的几个关键的模块 events 事件 executors 执行器 job 任务 jobstore
  • libcaffe Check failed: registry.count(type) == 1 (0 vs. 1) Unknown layer type: Input (known types: )

    在用libcaffe lib建立工程时 出现 Check failed registry count type 1 0 vs 1 Unknown layer type Input known types 错误 参考了两篇博文解决问题 主要思
  • warning: ignoring JAVA_HOME=D:\JDK; using bundled JDK报错解决

    warning ignoring JAVA HOME D JDK using bundled JDK报错原因是因为你JDK版本太低或者你的ElasticSearch版本太高降低版本即可 我的是JDK1 8我下载的是elasticsearch
  • 八皇后问题--回溯

    在刘汝佳老师的书中对于8皇后问题的分析 我感觉非常经典 8皇后问题可行的解 92个 回溯的定义 当把问题分解成若干的步骤并递归的求解时候 如果当前步骤没有合法的选择 则函数将返回上一级递归调用 这种现象称为回溯 这是这个原因 递归枚举算法常
  • uniapp 保存二维码到本地,如果不是本地图片需要先下载后保存。

    如果二维码不是固定的 是线上的就需要先去下载 baocuns 保存二维码 let that this uni showLoading title 保存中 uni downloadFile 先下载网络图片 转为临时路径图片 url that
  • 进制转换C语言实现(十进制转换为任意进制)

    程序实现功能 输入一个十进制数和R 表示要转换成R进制 输出转换后的数 事例 例如 输入 10 2 输出 1010 源代码如下 include
  • UE的rtsp插件崩溃过程排查

    Part1前言 Invideo插件是一个UE5的rtsp视频播放插件 当然还可以播放主流的其他视频协议 其开源地址如下https github com inveta InVideo 前段时间有网页反馈使用该插件进行播放视频的时候会有偶发程序
  • 如何学习计算机视觉?初学者怎么入门?

    学习计算机视觉需要一定的数学 编程和机器学习基础 以下是一些学习计算机视觉的步骤和资源 如何学习计算机视觉 初学者怎么入门 学习编程语言 计算机视觉的主要编程语言包括Python和C 可以学习Python或C 编程 掌握基本语法和编程思想
  • librtmp ssl 1.0.0 到 ssl 1.1.1

    openssl 版本更新了 导致 librtmp 库不能使用 于是查查资料 Compiler errors dereferencing pointer to incomplete type DH aka struct dh st 根据上面的
  • torch.cuda模块获取信息

    判断GPU是否可用 import torch print torch cuda is available 如果输出True则表示可以使用GPU 输出可使用GPU的数量 import torch print torch cuda device
  • 15 Flutter TabBarView和TabBar 定义顶部 Tab 切换

    Flutter TabBarView和TabBar 定义顶部 Tab 切换 1 属性 TabBar属性 说明 tabs 一系列标签控件 controller 标签选择变化控制器 isScrollable 是否可滚动 默认false indi
  • Floyd 算法,找出所有最短路径或最长路径 matlab (二)

    所有最短路径 在 一 中 我们获得了距离矩阵和路由矩阵 元胞 这个一个无向图 这是上次算出的距离矩阵和路由矩阵 接下来介绍如何根据这个路由矩阵 元胞 列出所有最短路径 结果存储在一个矩阵里 每一行代表一条最短路径的标号 定义列出所有最短路径
  • MQ可以用在哪些地方,解决什么问题?

    MQ kafka是以吞吐量高而闻名 不过其数据稳定性一般 而且无法保证消息有序性 阿里巴巴的RocketMQ基于Kafka的原理 利用Java代码打造 弥补了Kafka的缺点 继承了其高吞吐的优势 其客户端目前以Java为主 RabbitM