消息队列(MQ)

news2024/11/16 13:33:53

文章目录

  • 什么是消息队列
    • 定义
  • 消息队列的特性:
      • 1、解耦:
      • 2、削峰:
      • 3、异步:
  • 使用场景
    • 传统串行化设计
      • 串行化思想:
    • 并行处理调优
      • 高可用:
      • 高并发
      • 高性能
  • MQ的两种流派
  • MQ常见的问题
    • 1,mq如何避免消息堆积问题。
    • 2,如何避免重复消费问题
    • 3,如何保证消息不丢失
    • 4,如何保证消费的顺序一致性
    • 5,mq怎么用于保证redis和数据库的数据一致性
    • 6,消费者怎么知道mq里有消息了
    • 7,如果mq宕机后,生产者怎么处理。
    • 8,mq的消费策略

————————————————————————————————

什么是消息队列

定义

消息队列:一般我们会简称它为MQ(Message Queue)。
【消息队列就是一个存放消息的队列】
Message QueryMQ),消息队列中间件,很多初学者认为,MQ通过消息的发送和接受来实现程序的异步和解耦,mq主要用于异步操作,这个不是mq的真正目的,只不过是mq的应用,mq真正的目的是为了通讯。
他屏蔽了复杂的通讯协议,像常用的dubbo,http协议都是同步的。
这两种协议很难实现双端通讯,A调用B,B也可以主动调用A,而且不支持长连接。mq做的就是在这些协议上构建一个简单协议——生产者、消费者模型,mq带给我们的不是底层的通讯协议,而是更高层次的通讯模型。他定义了两个对象:发送数据的叫做生产者,接受消息的叫做消费者,我们可以无视底层的通讯协议,我们可以自己定义生产者消费者。

复习一下队列。

队列是一种先进先出的数据结构(线性结构)。和他相似的还有栈(先进后出)。

补充:

使用队列的还有一个场景就是线程池队列:有界队列和无界队列。用来存储任务。

消息队列:
有两个名词—生产者、消费者
生产者——生产新建
消费者——消费使用

消息队列的特性:

异步、削峰、解耦

1、解耦:

业务模块之间没有关联,一个服务挂掉不会影响其他业务,可以通过后续补偿或者分布式事务解决。
缺点:事务问题,只要使用消息队列,都会面临事务问题(无法保证原子性)。分布式事务解决框架。分布式事务般都遵循最终一致性。
就像高可用里面说的一样,发淘金币服务挂了,关下单什么关系,发淘金币服务挂了,我还是可以正常下单,只不过后期可以数据补偿或者分布式事务去解决这个问题。

2、削峰:

比如说我平时服务就只能支撑几万的qps,像淘宝京东那种秒杀,那时候服务突然打进来(如果采用第二种方案)那服务就会直接被压死了。但是如果采用消息队列,这秒杀进来的所有的请求都不会直接打到具体服务上,都会先打到消息队列里,然后我后面的服务再慢慢消费。
可以看看淘宝京东双11秒杀的时候,是不是有的时候慢是慢了点,但是服务起码没挂。等我秒杀结束之后,服务还能正常运转。
消息队列就像是一个三峡大坝,用来拦截上游给的压力。

3、异步:

连接消息队列的服务可以异步去执行。而且每次多增加一个步骤,我下单的代码是不平要动的,只需要再增加一个消费者即可。

使用场景

消息队列的三个最主要的作用是:异步、削峰、解耦,一定要烂熟于心。

传统串行化设计

先看看传统的设计(如果说业务体量小,并发不大,可以使用这种设计)
客户端调用下单服务,下单服务调用扣减库存,扣减库存中调用扣减淘金币……,调用完成再依次返回。
在这里插入图片描述
观察一下上面的设计,属于典型的串行化调用,这种设计模式有一个很大的优势,就是代码简单,出现问题很容易定位到问题。但是也有很多劣势,下面咱们从三高(高并发,高性能,高可用)三个方面去评审一下这个设计。

高可用: 这些服务假如有一个服务挂掉(宕机或者网络波动),就意味着我这个请求失败了,这样用户体验会极差,用户会频繁看到支付失败。
高并发: 因为这些操作都是由一个线程(主线程)去执行这些操作,所以当我们的QPS如果很高的话,很容易造成超时。
QPS:系统每秒钟收到的请求。
高性能: 因为上面这种设计模式是串行的,假设我的每次网络传输耗时200ms,业务处理需要20ms,完成上面那些操作需要耗时2s,这样用户体验也会很差(想象一下每次下单都需要等2s),如果用户下单后的操作越来越多,耗时只会越来越高。

所以在一个大型的互联网项目中,以上设计是完全不可取的(非核心模块除外)。

串行化思想:

  • 弊端1:耗时太长(低QPS);用户多,请求多,如果每个请求都要两秒,很容易造成请求堆积。
  • 弊端2:耦合性太强;随便一个服务挂掉,都会导致下单失败
  • 优点:写代码简单
    注: 挂掉有几种情况:服务真正的挂掉了;服务器网络波动,导致服务假死

并行处理调优

既然上面说的是串行模块,那么我们用自己的线程池把他改为并行的设计,再看评审一下。
所谓的并行设计就是原来由一个线程去串行做的逻辑,改为多个线程并行去做。
在这里插入图片描述
在这里插入图片描述

高可用:

高可用: 这些服务假如有一个服务挂掉(宕机或者网络波动),理论上讲,如果补偿服务做的出色的话,还是满足高可用的。(可以用try,catch)

高并发

高并发: 相比上面的设计,系统的吞吐量可以达到了很大程度上的提升。

高性能

高性能: 相比单线程的设计,因为很多业务是并行执行的,业务耗时会大幅减少,性能相比提高,所以相当于只有200*2+20,就可以返回。

上面这个设计看起来还是不错的设计,所以在很多这种串行调用,多次io的时候,我们就可以采用这种方案,上面这种设计也是多线程的一种实战应用。
弊端:
1.系统的可扩展性太差了。上面只是列举了4步,但是实际上会有几十步,这几十步放到代码里就会像屎堆一样,可维护性极差。每次加一个步骤,都要多调一个接口,然后重新发布一下服务。
2,系统的耦合性太高了。想象一下,几十个http调用放到一起并发执行,很有可能会影响其他的点,尤其是淘宝京东这种秒杀敏感的业务,和钱挂钩的业务,很容易出现p0级别的bug。
3,使用的业务本身的线程池,在并发很多的情况下,容易造成cpu的竞争。

(多线程处理三种方案) 进一步演化:
多线程处理 三种方案:采用多线程异步处理
1,主线程交给线程池里的线程去执行时,主线程等待,等我所有任务,执行完之后,主线程再去接着执行(查询做聚合的时候)
* 【主线程把任务扔给线程池,主线程等待,线程池的任务都执行完之后,主线程再返回给用户执行成功的消息】

2,主线程交给线程池去处理,就不管了(我要删除或修改一个东西,需要耗时2s)
* 【主线程等一段时间,不管线程池执行成没成功,都认为执行成功了,给用户返回执行成功】

3,主线程交给线程池去处理,主线程继续去执行其他的任务,等线程池里的任务执行完之后,去通知主线程,主线程在接着去执行后续的逻辑。
* 【主线程把任务扔给线程池之后,不等着线程池执行完,就去执行其他的,等线程池执行完之后就通知主线程,主线程再返回给用户执行成功的消息】
**注:**多线程在秒杀等高并发的场景下,容易造成CPU竞争。(虚拟机也是服务器)
消息队列

MQ的两种流派

1,有broker的
broker是什么,可以理解为是一个中转站。生产者将消息发送给他就结束自己的任务了,broker将消息主动推送给消费者(具体的将消息推送到哪个队列,或者说消费者主动请求)

  • 重topic
    • 必须要有topic
    • kafka:全球消息处理性能最快的一款mq
    • rocketmq:阿里内部的一个大神根据kafka的执行原理手写的,性能与kafka差不多,但是功能上比kafka要多,比如说顺序消费。
  • 轻topic
    • 可以没有topic,topic只是一种中转模式
    • rabbitmq

2,无broker的
* zeromq:没有使用broker,是直接使用socket进行通信。

MQ常见的问题

1,mq如何避免消息堆积问题。

消息堆积: 生产者的生产速率远远大于消费者的消费速率,使消息大批量的堆积在消息队列。
解决方案:
1,提升消费者的消费速率(增加消费者集群)【不常用】
2,消费者分批多线程去处理
3,限流,保证进入到消息队列的都是有用的消息

2,如何避免重复消费问题

什么是重复消费?
生产者可能发送一摸一样的消息(假如没做幂等性校验,发送了一模一样的修改密码的请求),消费者可能会消费失败(网络丢包),会重试。这样都会导致重复消费。(kafuka存在硬盘里面的,不会丢消息)
产生原因:

  • 1,生产者产生了两条一模一样的消息。
  • 2,消费者一条消息消费了多遍

消息重试: 消息重试一般发生于一个消费者发生了异常(网络波动或者系统假死),这个时候这个消费者就会通知生产者重新发送。就会带来重复消费的问题。
可以采用常用的幂等解决方案(分布式锁),全局id+业务场景保证唯一性。所有的重复提交问题,都可以用幂等性来解决。
为了保险起见,也可以在数据库上做好唯一索引。

3,如何保证消息不丢失

1,消息确认机制, 生产者必须确认消息成功刷盘到硬盘中,才确认消息发送成功。

acks 参数指定了必须要有多少个分区副本收到消息,生产者才会认为消息写入是成功的。这个参数对消息丢失的可能性有重要影响。该参数有如下选项。

  • 如果 acks=0 ,生产者在成功写入消息之前不会等待任何来自服务器的响应。也就是说,如果当中出现了问题,导致服务器没有收到消息,那么生产者就无从得知,消息也就丢失了。不过,因为生产者不需要等待服务器的响应,所以它可以以网络能够支持的最大速度发送消息,从而达到很高的吞吐量。
  • 如果 acks=1 ,只要集群的Leader节点收到消息,生产者就会收到一个来自服务器的成功响应。如果消息无法到达Leader节点(比如Leader节点崩溃,新的Leader还没有被选举出来),生产者会收到一个错误响应,为了避免数据丢失,生产者会重发消息。不过,如果一个没有收到消息的节点成为新Leader,消息还是会丢失。这个时候的吞吐量取决于使用的是同步发送还是异步发送。如果让发送客户端等待服务器的响应(通过调用 Future 对象的 get() 方法),显然会增加延迟(在网络上传输一个来回的延迟)。如果客户端使用回调,延迟问题就可以得到缓解,不过吞吐量还是会受发送中消息数量的限制(比如,生产者在收到服务器响应之前可以发送多少个消息)。
  • 如果 acks=-1(或all),只有当所有参与复制的节点全部收到消息时,生产者才会收到一个来自服务器的成功响应。这种模式是最安全的,它可以保证不止一个服务器收到消息,就算有服务器发生崩溃,整个集群仍然可以运行。不过,它的延迟比 acks=1 时更高,因为要等待不只一个服务器节点接收消息。

结合具体的业务场景来进行选择。
2,消息持久化机制, 作为mq中间件,会把消息持久化到硬盘
3,消费者必须确认消息消费成功, 否则进行重试,重试达到一定次数后,通知开发人员做好补偿措施。
关闭自动提交,当消费者消费的完成后,再手动提交,防止mq的自动提交,当消费者接收到消息后,mq以为消费者已经消费了,但这个时候消费者如果挂了,这条消息就没有被消费。

4,如何保证消费的顺序一致性

大多数的项目不需要保证顺序一致性,某些特殊场景必须保证顺序一致性,比如说,mq用于保证redis和mysql的数据一致性。
绑定同一个消费队列,消费的时候进行要注意如果使用了多线程处理,避免重新创建list,要在原来的list进行修改。

5,mq怎么用于保证redis和数据库的数据一致性

1,当执行update后,发送mq去通知消费者更新redis数据
优点:解耦,提高接口响应速度,有相应的补偿策略
缺点:延迟比较高
2,监听binlog日志,结合mq,去更新redis(canal实现)
优点:更加解耦
缺点:延迟更高
3,双删策略
更新前删一次,更新后删一次
如果不删除第二次,只删除第一次,执行提交但是还没提交成功的时间间隔内,如果有人执行查询,数据库的旧数据就会存在缓存中
如果不删除第一次,执行提交但是还没提交成功的时间间隔内,直接查到的是数据库的旧数据

6,消费者怎么知道mq里有消息了

两种方案:
1,mq主动通知(push)
当mq中有消息,就会通知消费者来进行消费。这种模型有一个致命伤,就是慢消费。
2,消费者轮询(pull)
消费者去轮询看看有没有自己要消费的消息。这种模型也有弊端就是消息延迟与忙等。
如果消费者的速度比发送者的速度慢很多,势必造成消息在mq的堆积。假设这些消息都是有用的无法丢弃的,消息就要一直在mq端保存。当然这还不是最致命的,最致命的是mq给消费者推送一堆无法处理的消息,消费者不是拒绝就是报错,然后来回踢皮球。
反观pull模式,消费者可以按需消费,不用担心自己处理不了的消息来骚扰自己,而mq堆积消息也会相对简单,无需记录每一个要发送消息的状态,只需要维护所有消息的队列和偏移量就可以了。所以消息量有限且到来的速度不均匀的情况,pull模式比较合适。
由于主动权在消费方,消费方无法准确地决定何时去拉取最新的消息。如果一次pull取到消息了还可以继续去pull,如果没有pull取到则需要等待一段时间重新pull。
但等待多久就很难判定了。当然也不是说延迟就没有解决方案了,业界较成熟的做法是从短时间开始(不会对mq有太大负担),然后指数级增长等待。比如开始等5ms,然后10ms,然后20ms,然后40ms……直到有消息到来,然后再回到5ms。
即使这样,依然存在延迟问题:假设40ms到80ms之间的50ms消息到来,消息就延迟了30ms,而且对于半个小时来一次的消息,这些开销就是白白浪费的。
在阿里的RocketMq里,有一种优化的做法—长轮询,来平衡推拉模型各自的缺点。基本思路是:消费者如果尝试拉取失败,不是直接返回,而是把连接挂在那里等待,服务端如果有新的消息到来,把连接复用起来,这也是不错的思路。但海量的长连接mq对系统的开销还是不容小觑的,还是要合理的评估时间间隔。

7,如果mq宕机后,生产者怎么处理。

生产者在向mq投递消息的时候,可以将要投递的消息记录下来(可以在数据库中插入一条数据,也可以输出相应的日志记录)后期可以编写定时任务,定期向mq发送之前发送不成功的消息。

8,mq的消费策略

集群消费: 同一个消费者集群,只能消费一条消息,但是一条消息可以被多个消费者集群消费。
广播消费: 通知集群中的所有节点都进行消费(涉及到数据分片处理的场景),对数据不敏感 的场景可以采用普通hash(比如发送推送),对数据敏感的场景可以采用hash环。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/107977.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何解决甲乙双方需求理解巨大偏差的问题?

1、对双方进行专业培训 需求分析人员对需求方应用领域不熟悉,而需求方对软件开发也不熟悉,通过对双方进行专业知识培训,让双方对用户专业领域和软件开发领域都有较为清晰的认识。在此基础上,需求方提出的需求更精准,双…

Java中的多线程——线程安全问题

作者:~小明学编程 文章专栏:JavaEE 格言:热爱编程的,终将被编程所厚爱。 目录 多线程所带来的不安全问题 什么是线程安全 线程不安全的原因 修改共享数据 修改操作不是原子的 内存可见性对线程的影响 指令重排序 解决线程…

一个高性能、无侵入的Java性能监控和统计工具,有点东西!

背景 随着所在公司的发展,应用服务的规模不断扩大,原有的垂直应用架构已无法满足产品的发展,几十个工程师在一个项目里并行开发不同的功能,开发效率不断降低。 于是公司开始全面推进服务化进程,把团队内的大部分工程…

你造Python中的上下文管理器是啥吗

上下文管理器(Context managers)让我们在需要的时候可以准确地分配或释放资源 Python中最常用的上下文管理例子就是with语句了,一般是在操作文件的时候,比如: 有PY基础的小伙伴都知道,上面的代码等价于: 对比两个例子…

python机器学习及深度学习在空间模拟与时间预测领域中的应用

了解机器学习的发展历史、计算原理、基本定义,熟悉机器学习方法的分类,常用机器学习方法,以及模型的评估与选择;熟悉数据预处理的流程,掌握python程序包的使用;理解机器学习在生态水文中的应用,…

使用Python绘制圣诞树教程(附源代码)

🤵‍♂️ 个人主页:艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞&#x1f4…

Qt Creator 运行LVGL模拟器

windows下用Qt Creator运行LVGL 8.2 背景 最近在学习LVGL,手头又没有硬件,好多网上资料介绍了如何在PC端模拟,纯C语言实现的库模拟的话也不会复杂,恰巧本人熟悉Qt Creator,那就用这个环境模拟吧,网上搜索…

为什么企业传统网络访问海外应用程序不稳定、速度慢?怎么解决?

外贸、游戏等行业经常会有跨网数据访问的需求,并且访问慢、卡是常见的问题。这其中主要的原因是网络访问速度与物理距离有直接关系。刨除距离原因,还有哪些因素影响了我们的访问呢?那么访问国站慢的影响因素有哪些? 在中国的国内用户,使用应…

下载安装npm,配置环境变量详细教程

要在本地运行项目,就需要安装npm,其次还需要配置项目依赖node-modules。今天我们就先安装npm npm下载安装一、安装1、下载2、勾选同意,下一步3、默认的存储位置即可,next4、不用勾选,next5、点击install6、等待安装完成…

通过 Mito 在 Python 中使用电子表格

在本文中,您将学习如何使用这个强大的库,该库能够自动执行某些 Pandas 任务并以非常快速的方式执行数据分析。 Mitosheet是什么? Mitosheet 是 Python 中可用的众多库之一,它实际上是 Python 和电子表格之间的融合,大大加快了数据分析过程。 安装过程 您可以安装在分析…

《Python多人游戏项目实战》第五节 断线重连

目录 5.1 模拟弱网状态 5.2 断线重连 5.3 优化玩家名称显示 5.4 完整代码下载地址 导致客户端和服务端断开连接的原因可能有以下三种: 服务端主动关闭连接。客户端窗口关闭,玩家退出游戏。客户端所在网络不给力(也叫做弱网)&…

Redis - Redis持久化:AOF和RDB

1. 为什么要持久化 Redis是内从数据库,宕机后数据会丢失;Redis重启后,为了快速恢复数据,提供了持久化机制;Redis有两种持久化方式:RDB和AOF,这也是Redis无畏宕机与快速恢复数据的杀手锏。 注意…

全球代表供应商!腾讯安全NDR再获Gartner认可

近日,国际研究机构Gartner发布了2022年《Market Guide for Network Detection and Response》(《网络检测和响应(NDR)市场指南》)(以下简称《报告》),腾讯安全被Gartner列为全球NDR市…

非零基础自学Golang 第17章 HTTP编程(上) 17.3 爬虫框架gocolly 17.3.1 gocolly简介

非零基础自学Golang 文章目录非零基础自学Golang第17章 HTTP编程(上)17.3 爬虫框架gocolly17.3.1 gocolly简介第17章 HTTP编程(上) 17.3 爬虫框架gocolly 我们在之前学习了如何使用标准库实现HTTP爬虫【其实也不算,就实现了简单的请求,但是爬虫不就是这…

别乱用了,用新的。Go SliceHeader 和 StringHeader 将会被废弃!

大家好,我是煎鱼。Go 语言中有个很经典的 (Slice|String)Header,经常出现在大家视野中,为此我写了《Go SliceHeader 和 StringHeader,你知道吗?》给大家介绍,避免被面试官卷到。以重点来讲,Slic…

Alibaba送给开发人员的“礼物”:Java架构成长笔记,深入内核,拒绝蒙圈

提起阿里,行外人联想到的关键词无非是“交易”、“淘宝”、“支付宝”,但对于程序员来说,阿里庞大的技术体系才是最吸引人的。实际上阿里作为国内一线互联网公司的头把交椅,内部的技术体系和发展都是备受关注的,对于程…

【javaScript总结归纳】字符串常用方法总结

前言 在js中我们对字符串进行一部分截取,可以使用slice()函数截取,也可以直接用substring()函数来截取,但是截取也有可能出bug const str小𠮷和小𧨁今天吃了50块钱的KFC console.log(str.slice(0,5)); 可以在控制台看…

评估EtherCAT从站节点解决方案

本系列博客文章的第1部分介绍了用于C2000™微控制器的EtherCAT从站堆栈解决方案的市场机遇,以及从站堆栈开发快速入门的三个阶段指南。第2部分详细说明了TIC2000 MCU EtherCAT实施的特点和优势。第3部分分别介绍了使用EtherCAT从站和C2000 Delfino MCU controlCARD套…

Linux【windows使用xshell连接本地虚拟机】【Mac使用terminal连接本地虚拟机】

文章目录对于本地虚拟机的配置使用Mac的terminal的ssh连接本地虚拟机windows使用xshell连接本地虚拟机对于本地虚拟机的配置 IP地址和子网掩码。 在虚拟机中使用ping命令判断虚拟机到宿主机是否是连通的。(不通的话,关闭Windows防火墙,再试一…

python+pyhyper实现识别图片中的车牌号

背景 最近领导给布置了一个基于图片识别车牌号的工具开发任务,然后就去研究实现逻辑,自己根据opencv写了一个小demo,发现不仅速度慢而且成功率极低。然后,就找到了Hyperlpr开源项目。 环境搭建 排雷1:有教程说在git…