mfc 消息消息队列概念_消息队列面试连环问

最近我一直扎在消息队列实现细节之中无法自拔,已经写了 3 篇Kafka源码分析,还剩很多没肝完。之前还存着RocketMQ源码分析还没整理。今儿暂时先跳出来盘一盘大方向上的消息队列有哪些核心注意点。

核心点有很多,为了更贴合实际场景,我从常见的面试问题入手:

  • 如何保证消息不丢失?

  • 如何处理重复消息?

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

  • 如何处理消息堆积?

当然在剖析这几个问题之前需要简单的介绍下什么是消息队列,消息队列常见的一些基本术语和概念

接下来进入正文。

什么是消息队列

来看看维基百科怎么说的,顺带学学英语这波不亏:

In computer science, message queues and mailboxes are software-engineering components typically used for inter-process communication (IPC), or for inter-thread communication within the same process. They use a queue for messaging – the passing of control or of content. Group communication systems provide similar kinds of functionality.

翻译一下:在计算机科学领域,消息队列和邮箱都是软件工程组件,通常用于进程间或同一进程内的线程通信。它们通过队列来传递消息-传递控制信息或内容,群组通信系统提供类似的功能。

简单的概括下上面的定义:消息队列就是一个使用队列来通信的组件

上面的定义没有错,但就现在而言我们日常所说的消息队列常常指代的是消息中间件,它的存在不仅仅只是为了通信这个问题。

为什么需要消息队列

从本质上来说是因为互联网的快速发展,业务不断扩张,促使技术架构需要不断的演进。

从以前的单体架构到现在的微服务架构,成百上千的服务之间相互调用和依赖。从互联网初期一个服务器上有 100 个在线用户已经很了不得,到现在坐拥10亿日活的微信。我们需要有一个「东西」来解耦服务之间的关系、控制资源合理合时的使用以及缓冲流量洪峰等等。

消息队列就应运而生了。它常用来实现:异步处理、服务解耦、流量控制

异步处理

随着公司的发展你可能会发现你项目的请求链路越来越长,例如刚开始的电商项目,可以就是粗暴的扣库存、下单。慢慢地又加上积分服务、短信服务等。这一路同步调用下来客户可能等急了,这时候就是消息队列登场的好时机。

调用链路长、响应就慢了,并且相对于扣库存和下单,积分和短信没必要这么的 "及时"。因此只需要在下单结束那个流程,扔个消息到消息队列中就可以直接返回响应了。而且积分服务和短信服务可以并行的消费这条消息。

可以看出消息队列可以减少请求的等待,还能让服务异步并发处理,提升系统总体性能

eadecc7b98fb3bdff52a727d2b17f374.png

服务解耦

上面我们说到加了积分服务和短信服务,这时候可能又要来个营销服务,之后领导又说想做个大数据,又来个数据分析服务等等。

可以发现订单的下游系统在不断的扩充,为了迎合这些下游系统订单服务需要经常地修改,任何一个下游系统接口的变更可能都会影响到订单服务,这订单服务组可疯了,真 ·「核心」项目组

619f698f58e3b3e3c694da949809eb43.png

所以一般会选用消息队列来解决系统之间耦合的问题,订单服务把订单相关消息塞到消息队列中,下游系统谁要谁就订阅这个主题。这样订单服务就解放啦!

92ea0a0bd67d77dccf6eaed96bb9f287.png

流量控制

想必大家都听过「削峰填谷」,后端服务相对而言都是比较「弱」的,因为业务较重,处理时间较长。像一些例如秒杀活动爆发式流量打过来可能就顶不住了。因此需要引入一个中间件来做缓冲,消息队列再适合不过了。

网关的请求先放入消息队列中,后端服务尽自己最大能力去消息队列中消费请求。超时的请求可以直接返回错误。

当然还有一些服务特别是某些后台任务,不需要及时地响应,并且业务处理复杂且流程长,那么过来的请求先放入消息队列中,后端服务按照自己的节奏处理。这也是很 nice 的。

上面两种情况分别对应着生产者生产过快和消费者消费过慢两种情况,消息队列都能在其中发挥很好的缓冲效果。

698e6283cee4f2926cf6c2e31ee3e5a9.png

注意

引入消息队列固然有以上的好处,但是多引入一个中间件系统的稳定性就下降一层,运维的难度抬高一层。因此要权衡利弊系统是演进的

消息队列基本概念

消息队列有两种模型:队列模型发布/订阅模型

队列模型

生产者往某个队列里面发送消息,一个队列可以存储多个生产者的消息,一个队列也可以有多个消费者, 但是消费者之间是竞争关系,即每条消息只能被一个消费者消费。

0ec93fd8b851951e7575c07b292233fa.png

发布/订阅模型

为了解决一条消息能被多个消费者消费的问题,发布/订阅模型就来了。该模型是将消息发往一个Topic即主题中,所有订阅了这个 Topic 的订阅者都能消费这条消息。

其实可以这么理解,发布/订阅模型等于我们都加入了一个群聊中,我发一条消息,加入了这个群聊的人都能收到这条消息。那么队列模型就是一对一聊天,我发给你的消息,只能在你的聊天窗口弹出,是不可能弹出到别人的聊天窗口中的。

讲到这有人说,那我一对一聊天对每个人都发同样的消息不就也实现了一条消息被多个人消费了嘛。

是的,通过多队列全量存储相同的消息,即数据的冗余可以实现一条消息被多个消费者消费。RabbitMQ 就是采用队列模型,通过 Exchange 模块来将消息发送至多个队列,解决一条消息需要被多个消费者消费问题。

这里还能看到假设群聊里除我之外只有一个人,那么此时的发布/订阅模型和队列模型其实就一样了。

5b26d7bb24115270648cab07b606321d.png

小结一下

队列模型每条消息只能被一个消费者消费,而发布/订阅模型就是为让一条消息可以被多个消费者消费而生的,当然队列模型也可以通过消息全量存储至多个队列来解决一条消息被多个消费者消费问题,但是会有数据的冗余。

发布/订阅模型兼容队列模型,即只有一个消费者的情况下和队列模型基本一致。

RabbitMQ 采用队列模型,RocketMQKafka 采用发布/订阅模型。

接下来的内容都基于发布/订阅模型

常用术语

一般我们称发送消息方为生产者 Producer,接受消费消息方为消费者Consumer,消息队列服务端为Broker

消息从Producer发往BrokerBroker将消息存储至本地,然后ConsumerBroker拉取消息,或者Broker推送消息至Consumer,最后消费。

ee0ffab70fd3f0d2b9bb883a451d20fc.png

为了提高并发度,往往发布/订阅模型还会引入队列或者分区的概念。即消息是发往一个主题下的某个队列或者某个分区中。RocketMQ中叫队列,Kafka叫分区,本质一样。

例如某个主题下有 5 个队列,那么这个主题的并发度就提高为 5 ,同时可以有 5 个消费者并行消费该主题的消息。一般可以采用轮询或者 key hash 取余等策略来将同一个主题的消息分配到不同的队列中。

与之对应的消费者一般都有组的概念 Consumer Group, 即消费者都是属于某个消费组的。一条消息会发往多个订阅了这个主题的消费组。

假设现在有两个消费组分别是Group 1Group 2,它们都订阅了Topic-a。此时有一条消息发往Topic-a,那么这两个消费组都能接收到这条消息。

然后这条消息实际是写入Topic某个队列中,消费组中的某个消费者对应消费一个队列的消息。

在物理上除了副本拷贝之外,一条消息在Broker中只会有一份,每个消费组会有自己的offset即消费点位来标识消费到的位置。在消费点位之前的消息表明已经消费过了。当然这个offset是队列级别的。每个消费组都会维护订阅的Topic下的每个队列的offset

来个图看看应该就很清晰了。

0d9fc5347572d850ad0abe8814fd8282.png

基本上熟悉了消息队列常见的术语和一些概念之后,咱们再来看看消息队列常见的核心面试点。

如何保证消息不丢失

就我们市面上常见的消息队列而言,只要配置得当,我们的消息就不会丢。

先来看看这个图,

2ded86f02fcc2ea021f24b2e9b5542c8.png

可以看到一共有三个阶段,分别是生产消息、存储消息和消费消息。我们从这三个阶段分别入手来看看如何确保消息不会丢失。

生产消息

生产者发送消息至Broker,需要处理Broker的响应,不论是同步还是异步发送消息,同步和异步回调都需要做好try-catch,妥善的处理响应,如果Broker返回写入失败等错误消息,需要重试发送。当多次发送失败需要作报警,日志记录等。

这样就能保证在生产消息阶段消息不会丢失。

存储消息

存储消息阶段需要在消息刷盘之后再给生产者响应,假设消息写入缓存中就返回响应,那么机器突然断电这消息就没了,而生产者以为已经发送成功了。

如果Broker是集群部署,有多副本机制,即消息不仅仅要写入当前Broker,还需要写入副本机中。那配置成至少写入两台机子后再给生产者响应。这样基本上就能保证存储的可靠了。一台挂了还有一台还在呢(假如怕两台都挂了..那就再多些)。

那假如来个地震机房机子都挂了呢?emmmmmm...大公司基本上都有异地多活。

那要是这几个地都地震了呢?emmmmmm...这时候还是先关心关心人吧。

912d4f16e4653f063020f71a47c74235.png

消费消息

这里经常会有同学犯错,有些同学当消费者拿到消息之后直接存入内存队列中就直接返回给Broker消费成功,这是不对的。

你需要考虑拿到消息放在内存之后消费者就宕机了怎么办。所以我们应该在消费者真正执行完业务逻辑之后,再发送给Broker消费成功,这才是真正的消费了。

所以只要我们在消息业务逻辑处理完成之后再给Broker响应,那么消费阶段消息就不会丢失。

小结一下

可以看出,保证消息的可靠性需要三方配合

生产者需要处理好Broker的响应,出错情况下利用重试、报警等手段。

Broker需要控制响应的时机,单机情况下是消息刷盘后返回响应,集群多副本情况下,即发送至两个副本及以上的情况下再返回响应。

消费者需要在执行完真正的业务逻辑之后再返回响应给Broker

但是要注意消息可靠性增强了,性能就下降了,等待消息刷盘、多副本同步后返回都会影响性能。因此还是看业务,例如日志的传输可能丢那么一两条关系不大,因此没必要等消息刷盘再响应。

如果处理重复消息

我们先来看看能不能避免消息的重复。

假设我们发送消息,就管发,不管Broker的响应,那么我们发往Broker是不会重复的。

但是一般情况我们是不允许这样的,这样消息就完全不可靠了,我们的基本需求是消息至少得发到Broker上,那就得等Broker的响应,那么就可能存在Broker已经写入了,当时响应由于网络原因生产者没有收到,然后生产者又重发了一次,此时消息就重复了。

再看消费者消费的时候,假设我们消费者拿到消息消费了,业务逻辑已经走完了,事务提交了,此时需要更新Consumer offset了,然后这个消费者挂了,另一个消费者顶上,此时Consumer offset还没更新,于是又拿到刚才那条消息,业务又被执行了一遍。于是消息又重复了。

可以看到正常业务而言消息重复是不可避免的,因此我们只能从另一个角度来解决重复消息的问题。

关键点就是幂等。既然我们不能防止重复消息的产生,那么我们只能在业务上处理重复消息所带来的影响。

58e4d9d5d456ab76d4645d16a62383c0.png

幂等处理重复消息

幂等是数学上的概念,我们就理解为同样的参数多次调用同一个接口和调用一次产生的结果是一致的。

例如这条 SQLupdate t1 set money = 150 where id = 1 and money = 100; 执行多少遍money都是150,这就叫幂等。

因此需要改造业务处理逻辑,使得在重复消息的情况下也不会影响最终的结果。

可以通过上面我那条 SQL 一样,做了个前置条件判断,即money = 100情况,并且直接修改,更通用的是做个version即版本号控制,对比消息中的版本号和数据库中的版本号。

或者通过数据库的约束例如唯一键,例如insert into update on duplicate key...

或者记录关键的key,比如处理订单这种,记录订单ID,假如有重复的消息过来,先判断下这个ID是否已经被处理过了,如果没处理再进行下一步。当然也可以用全局唯一ID等等。

基本上就这么几个套路,真正应用到实际中还是得看具体业务细节

如何保证消息的有序性

有序性分:全局有序和部分有序

全局有序

如果要保证消息的全局有序,首先只能由一个生产者往Topic发送消息,并且一个Topic内部只能有一个队列(分区)。消费者也必须是单线程消费这个队列。这样的消息就是全局有序的!

不过一般情况下我们都不需要全局有序,即使是同步MySQL Binlog也只需要保证单表消息有序即可。

56ee871c2506f83438bf3939f83eedd9.png

部分有序

因此绝大部分的有序需求是部分有序,部分有序我们就可以将Topic内部划分成我们需要的队列数,把消息通过特定的策略发往固定的队列中,然后每个队列对应一个单线程处理的消费者。这样即完成了部分有序的需求,又可以通过队列数量的并发来提高消息处理效率。

17d88215566a86a9585168b83441583d.png

图中我画了多个生产者,一个生产者也可以,只要同类消息发往指定的队列即可。

如果处理消息堆积

消息的堆积往往是因为生产者的生产速度与消费者的消费速度不匹配。有可能是因为消息消费失败反复重试造成的,也有可能就是消费者消费能力弱,渐渐地消息就积压了。

因此我们需要先定位消费慢的原因,如果是bug则处理 bug ,如果是因为本身消费能力较弱,我们可以优化下消费逻辑,比如之前是一条一条消息消费处理的,这次我们批量处理,比如数据库的插入,一条一条插和批量插效率是不一样的。

假如逻辑我们已经都优化了,但还是慢,那就得考虑水平扩容了,增加Topic的队列数和消费者数量,注意队列数一定要增加,不然新增加的消费者是没东西消费的。一个Topic中,一个队列只会分配给一个消费者

当然你消费者内部是单线程还是多线程消费那看具体场景。不过要注意上面提高的消息丢失的问题,如果你是将接受到的消息写入内存队列之后,然后就返回响应给Broker,然后多线程向内存队列消费消息,假设此时消费者宕机了,内存队列里面还未消费的消息也就丢了。

最后

上面的几个问题都是我们在使用消息队列的时候经常能遇到的问题,并且也是面试关于消息队列方面的核心考点。今天没有深入具体消息队列的细节,但是套路就是这么个套路,大方向上搞明白很关键。之后再接着写有关Kafka的源码分析文章,有兴趣的小伙伴请耐心等待。

- END -

最近整理一份面试资料《Java技术栈学习手册》,覆盖了Java技术、面试题精选、Spring全家桶、Nginx、SSM、微服务、数据库、数据结构、架构等等。获取方式:点“ 在看,关注公众号 Java后端 并回复 777 领取,更多内容陆续奉上。读 1. 13000 字的 Spring MVC 总结2. 推荐个 Java 开源商城项目3. 文件系统:隐匿在 Linux 背后的机制4. 牛逼!这篇文章让我重新认识了并发编程

5. 955 不加班公司名单:955.WLB

25f727744523220206887a8573dc179a.png

在看 92bcd7011243f3f66548bad76a18c6c2.png

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

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

相关文章

如何用增长的思维做提效?

简介: 埋点作为记录用户行为的常规手段,伴随着前端技术的发展早已历经春秋,不过直到“增长黑客”系列理论出现,才真正让埋点分析变得内涵丰富且有章可循。 作者 | 金戟 来源 | 阿里技术公众号 埋点作为记录用户行为的常规手段&am…

ajax返回list前台遍历_List、set集合接口分析

一、List接口详解1、List接口有三个实现类,ArrayList、LinkedList、Vector2、三个实现类的异同点:(1)ArrayList: 作为list接口的主要实现类;线程不安全,效率高;底层使用Object[]存储&#xff08…

聚焦 | 数据湖分析如何面向对象存储OSS进行优化?

简介: 最佳实践,以DLA为例子。DLA致力于帮助客户构建低成本、简单易用、弹性的数据平台,比传统Hadoop至少节约50%的成本。其中DLA Meta支持云上15种数据数据源(OSS、HDFS、DB、DW)的统一视图,引入多租户、元…

如何把极坐标化为直角坐标_2019高考100题之063(极坐标)

分析&#xff1a;如果你对过原点的直线的参数方程(xtcosθ&#xff0c;ytsinθ(参数t∈R))理解透彻了&#xff0c;那么极坐标也就没有任何问题了&#xff0c;特别是对于ρ<0的理解&#xff0c;就和t<0类似.教材上说了不作特殊说明&#xff0c;ρ都是大于零的&#xff0c;…

c语言队列作用,队列(C语言)

一、定义一种可以实现“先进先出”的存储结构。二、分类1、链式队列&#xff1a;用链表实现。2、静态队列&#xff1a;用数组实现。静态队列通常都必须是循环队列。3、循环队列(1)循环队列需要几个参数来确定&#xff1f;需要2个参数来确定&#xff1a;front、rear(2)循环队列各…

2021银行共探转型新动能:大行酝酿质变 小行跨越数字鸿沟

2021年&#xff0c;我国“十四五”规划开篇启程&#xff0c;数字经济蓬勃发展&#xff0c;银行业紧跟国家发展大局&#xff0c;全力推进数字化转型向纵深发展&#xff0c;探寻行业新动能&#xff0c;积极参与全社会数字生态建设&#xff0c;为数字中国高质量发展贡献金融力量。…

如何构建一个拖垮整个公司的运维系统

简介&#xff1a; 人肉运维&#xff0c;不在 DevOps 中转型&#xff0c;就在自动化中消亡。云化时代的运维&#xff0c;需要的是高铁&#xff0c;而不是“跑的更快的马车”。6月25日&#xff0c;数智创新行上海站智能运维专场&#xff0c;期待您的参与。 原文链接 本文为阿里云…

idea 安装php插件_免费版的 IDEA 为啥不能使用 Tomcat ?

程序员的成长之路互联网/程序员/技术/资料共享 关注阅读本文大概需要 2 分钟。来自&#xff1a;https://urlify.cn/2Ifiiiidea有两大版本&#xff0c;一个是Ultimate版本&#xff0c;一个是Community版&#xff0c;ultimate是需要收费的&#xff0c;Community版是开源免费的。然…

RocketMQ 千锤百炼--哈啰在分布式消息治理和微服务治理中的实践

简介&#xff1a; 随着公司业务的不断发展&#xff0c;流量也在不断增长。我们发现生产中的一些重大事故&#xff0c;往往是被突发的流量冲跨的&#xff0c;对流量的治理和防护&#xff0c;保障系统高可用就尤为重要。 作者&#xff5c;梁勇 ​ 背景 ​ 哈啰已进化为包括两轮…

休闲食品行业如何数字化升级,腾讯云和卫龙辣条一起打了个样

11月26日&#xff0c;腾讯云与卫龙集团达成战略合作&#xff0c;双方将整合各自优势资源&#xff0c;助力卫龙集团建设专有云平台&#xff0c;围绕生产、运营、管理层面进行全链路数字化&#xff0c;加速卫龙集团转型升级&#xff0c;打造休闲食品行业标杆。 作为一家年销售超过…

Vite + React 组件开发实践

简介&#xff1a; 毫不夸张的说&#xff0c;Vite 给前端带来的绝对是一次革命性的变化。或者也可以说是 Vite 背后整合的 esbuild 、 Browser es modules、HMR、Pre-Bundling 等这些社区中关于 JS 编译发展的先进工具和思路&#xff0c;在 Vite 这样的整合推动下&#xff0c;给…

canvas全局合成画月牙_GIF动态图,视频?都能用Python转换成字符画图像

字符画是一种由字母、标点或其他字符组成的图画&#xff0c;它产生于互联网时代&#xff0c;在聊天软件中使用较多&#xff0c;本文我们看一下如何将自己喜欢的图片转成字符画。静态图片首先&#xff0c;我们来演示将静态图片转为字符画&#xff0c;功能实现主要用到的 Python …

开发者看过来,5 行代码实现身份认证,Authing 如何做到的?

在没有学编程前&#xff0c;可能我们不会想到看起来简单的注册登录功能&#xff0c;其实并不简单&#xff0c;背后可能需要考虑&#xff1a; 1、支持用户用手机验证码、邮箱验证码登录&#xff1b; 2、用户连续登录失败&#xff0c;为了防止暴力破解&#xff0c;需考虑 24 小…

用c语言绘制自定义图形,Android使用自定义View绘图

使用自定义 View 绘图实例 MyViewCanvasDemo 自定义一个名为 MyView 的 View 类&#xff0c;并在其 onDraw() 方法中绘制简单的图像&#xff0c;运行效果如图 1 所示。图 1 简单的 View 绘图实例 MyViewCanvasDemo 没有使用布局文件&#xff0c;而是将自定义的 MyView 对象显示…

如何构建企业出海的“免疫力“?深入解读阿里云CDN安全能力

简介&#xff1a; 随着信息技术快速发展与应用&#xff0c;产业数字化和智能化趋势正日益加深&#xff0c;企业信息安全与防护被提升到前所有未有的高度。阿里云CDN经过10多年的技术发展时间&#xff0c;已逐步构筑一个边缘云的安全网络立体防护体系&#xff0c;包含了全链路安…

使用率激增 250%,这份报告再次将 Serverless 推向幕前

简介&#xff1a; 本文是对 Datadog 最新的一份 Serverless 报告的解读&#xff0c;欢迎大家留言讨论。 每项新技术的产生和演进过程中&#xff0c;都会有他自己的拥趸&#xff0c;也会有持怀疑论者。Serverless 的美在于他可以尽可能的解放客户在基础设施上的投入&#xff0c;…

dev用不了_跟风喊AMD YES?很多生产力项目,你必须用IU

大家好&#xff0c;我是小匠。现在的电脑市场中&#xff0c;高喊AMD YES几乎已经成为了一种政治正确了&#xff0c;尤其是在所谓的“生产力需求”的领域中。各大评测结果中也几乎都是AMD吊打Intel的局面。然而AU真的在所有生产力项目中都吊打IU吗&#xff1f;我可以负责任的告诉…

云计算到底是谁发明的?

作者 | 小枣君来源 | 鲜枣课堂&#xff08;ID&#xff1a;xzclasscom&#xff09;大家都在讨论云计算、云原生&#xff0c;那你知道云计算是谁发明的吗&#xff1f;说到云计算的起源&#xff0c;公众普遍认为&#xff0c;谷歌前 CEO 埃里克施密特是云计算概念的第一个提出者。2…

c语言静态变量存在堆还是栈,c 类 static 函数 什么样是静态变量?嵌入式C语言的堆栈管理如何实现...

C语言中静态变量是什么意思&#xff0c;有什么作用&#xff0c;static在数据类型前面表示什么最近刚看了C存储类的章节。所以来说说。C语言为变量提供了⑤种不同的存储模型&#xff0c;或者说是存储类。①个变量可以用存储时期描述&#xff0c;也可以用作用域描述&#xff0c;也…

如何专业化监控一个Kubernetes集群?

简介&#xff1a; 本文会介绍 Kubernetes 可观测性系统的构建&#xff0c;以及基于阿里云云产品实现 Kubernetes 可观测系统构建的最佳实践。 作者&#xff1a;佳旭 阿里云容器服务技术专家 引言 Kubernetes 在生产环境应用的普及度越来越广、复杂度越来越高&#xff0c;随之而…