原创

什么是消息队列

什么是消息队列

字义

简称MQ(Message Queue),翻译过来就是消息队列

背景

消息队列已经逐渐成为企业应用系统内部通信的核心手段。它具有低耦合可靠投递广播流量控制最终一致性等一系列功能。当前使用较多的消息队列RabbitMQRocketMQActiveMQKafkaZeroMQMetaMQ等,而部分数据库RedisMySQL以及phxsql也可实现消息队列的功能。

概念

消息队列是指利用高效可靠消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成。
可以简单理解为:把要传输的数据放在队列中。
生产者:往队列放消息
消费者:从队列读消息,读消息这个动作叫做消费

(可以看出队列是一种先进先出的数据结构)

通过提供消息传递消息排队模型,它可以在分布式环境下提供应用解耦弹性伸缩冗余存储流量削峰异步通信数据同步等等功能,其作为分布式系统架构中的一个重要组件,有着举足轻重的地位。

为什么使用消息队列

当你需要使用消息队列时,首先需要考虑它的必要性。可以使用消息队列的场景有很多,最常用的几种,是做应用程序松耦合、异步处理模式、发布与订阅、最终一致性、错峰流控和日志缓冲等。反之,如果需要强一致性,关注业务逻辑的处理结果,则使用RPC显得更为合适(比如dubbo)。

如何跟老婆解释什么是RPC

1、解耦

在这里插入图片描述
相安无事的过了几天…
在这里插入图片描述
又过了两天…
在这里插入图片描述
这天负责系统A的猿快下班了…
在这里插入图片描述
A系统的程序猿每天改来改去,不胜其烦,正当他烦恼的时候…
在这里插入图片描述
最后他变强了…

变强之后,负责A系统的猿决定用一种更强的方式来解决这个问题…
在这里插入图片描述
他让系统A把这个orderId写入到消息队列,其他系统从队列里拿数据(消费),这样就再也不用烦了

  • 系统A只负责将数据写入队列。东西我放这了,你们随意拿,反正我的代码是不改了。
  • 某个系统挂了,跟A系统无关。

这就实现了解耦

应用场景

  • 系统之间不是强耦合的,消息接受者可以随意增加,而不需要修改消息发送者的代码消息发送者的成功不依赖消息接受者(比如:有些银行接口不稳定,但调用方并不需要依赖这些接口)。
  • 不强依赖于非本系统的核心流程,对于非核心流程,可以放到消息队列中让消息消费者去按需消费,而不影响核心主流程

2、异步/提速

你在某个软件注册账号,系统收到的注册请求后会进行这些操作,整个过程需要900ms…
在这里插入图片描述
但是对于用户来说,注册功能实际只需要第一步,只要服务端将他的账户信息存到数据库中他便可以登录上去做他想做的事情了。至于其他的事情,非要在这一次请求中全部完成么?值得用户浪费时间等你处理这些对他来说无关紧要的事情么?所以实际当第一步做完后,服务端就可以把其他的操作放入对应的消息队列中然后马上返回用户结果,由消息队列异步的进行这些操作。
在这里插入图片描述
这样接口的速度就快多了!

应用场景

  • 非核心流程异步化,减少系统响应时间,提高吞吐量。例如:短信通知、终端状态推送、App推送、用户注册等
  • 消息队列一般都内置了高效的通信机制,因此也可以用于单纯的消息通讯,比如实现点对点消息队列或者聊天室等

3、流量削峰和流控

某网上商城每年要搞一次年中大促。平时访问量较小,一切都风平浪静。但是一到大促,访问量多了起来…
在这里插入图片描述
系统处理不过来,
在这里插入图片描述
这样,系统根据自己的能力去拉取请求,就不会出现系统崩了的情况。虽然有积压,但是也只是短暂的,高峰过后,系统很快就能把积压的请求处理完

应用场景

上下游系统处理能力存在差距的时候,利用消息队列做一个通用的“漏斗”,进行限流控制。在下游有能力处理的时候,再进行分发。

4、广播

生产者/消费者模式,只需要关心消息是否送达队列,至于谁希望订阅和需要消费,是下游的事情,无疑极大地减少了开发和联调的工作量。
在这里插入图片描述

一个形象的例子

小红是小明的姐姐。

小红希望小明多读书,常寻找好书给小明看,之前的方式是这样:小红问小明什么时候有空,把书给小明送去,并亲眼监督小明读完书才走。久而久之,两人都觉得麻烦。

后来的方式改成了:小红对小明说「我放到书架上的书你都要看」,然后小红每次发现不错的书都放到书架上,小明则看到书架上有书就拿下来看。

书架就是一个消息队列,小红是生产者,小明是消费者。

这带来的好处有:

1、小红想给小明书的时候,不必问小明什么时候有空,亲手把书交给他了,小红只把书放到书架上就行了。这样小红小明的时间都更自由。

2.小红相信小明的读书自觉和读书能力,不必亲眼观察小明的读书过程,小红只要做一个放书的动作,很节省时间。

3.当明天有另一个爱读书的小伙伴小强加入,小红仍旧只需要把书放到书架上,小明和小强从书架上取书即可(唔,姑且设定成多个人取一本书可以每人取走一本吧,可能是拷贝电子书或复印,暂不考虑版权问题)。

4.书架上的书放在那里,小明阅读速度快就早点看完,阅读速度慢就晚点看完,没关系,比起小红把书递给小明并监督小明读完的方式,小明的压力会小一些。

这就是消息队列的四大好处:

1.解耦
每个成员不必受其他成员影响,可以更独立自主,只通过一个简单的容器来联系。
小红甚至可以不知道从书架上取书的是谁,小明也可以不知道往书架上放书的人是谁,在他们眼里,都只有书架,没有对方。
毫无疑问,与一个简单的容器打交道,比与复杂的人打交道容易一万倍,小红小明可以自由自在地追求各自的人生。

2.异步/提速
小红选择相信「把书放到书架上,别的我不问」,为自己节省了大量时间。
小红很忙,只能抽出五分钟时间,但这时间足够把书放到书架上了。

3.广播
小红只需要劳动一次,就可以让多个小伙伴有书可读,这大大地节省了她的时间,也让新的小伙伴的加入成本很低。

4.削峰
假设小明读书很慢,如果采用小红每给一本书都监督小明读完的方式,小明有压力,小红也不耐烦。
反正小红给书的频率也不稳定,如果今明两天连给了五本,之后隔三个月才又给一本,那小明只要在三个月内从书架上陆续取走五本书读完就行了,压力就不那么大了。

当然,使用消息队列也有其成本:

1.引入复杂度
毫无疑问,「书架」这东西是多出来的,需要地方放它,还需要防盗。

2.暂时的不一致性
假如妈妈问小红「小明最近读了什么书」,在以前的方式里,小红因为亲眼监督小明读完书了,可以底气十足地告诉妈妈,但新的方式里,小红回答妈妈之后会心想「小明应该会很快看完吧……」
这中间存在着一段「妈妈认为小明看了某书,而小明其实还没看」的时期,当然,小明最终的阅读状态与妈妈的认知会是一致的,这就是所谓的「最终一致性」。

那么,该使用消息队列的情况需要满足什么条件呢?

1.生产者不需要从消费者处获得反馈
小红放完书之后小明到底看了没有,小红根本不问,她默认他是看了,否则就只能用原来的方法监督到看完了。

2.容许短暂的不一致性
妈妈可能会发现「有时候据说小明看了某书,但事实上他还没看」,只要妈妈满意于「反正他最后看了就行」,异步处理就没问题。
如果妈妈对这情况不能容忍,对小红大发雷霆,小红也就不敢用书架方式了。

3.确实是用了有效果
即解耦、提速、广播、削峰这些方面的收益,超过放置书架、监控书架这些成本。
否则如果是盲目照搬,「听说老赵家买了书架,咱们家也买一个」,买回来却没什么用,只是让步骤变多了,还不如直接把书递给对方呢,那就不对了。

消息队列的两种模式

JMS规范目前支持两种消息模型:点对点(point to point, queue)和发布/订阅(publish/subscribe,topic)。

点对点(不可重复消费)

Queue支持存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费。
在这里插入图片描述

发布/订阅

发布到topic的消息会被所有订阅者消费。(没有订阅就不会消费)
在这里插入图片描述
支持订阅组的发布订阅模式
发布订阅模式下,当发布者消息量很大时,显然单个订阅者的处理能力是不足的。实际上现实场景中是多个订阅者节点组成一个订阅组负载均衡消费topic消息即分组订阅,这样订阅者很容易实现消费能力线性扩展。可以看成是一个topic下有多个Queue,每个Queue是点对点的方式,Queue之间是发布订阅方式。
在这里插入图片描述

区别

点对点模式

生产者发送一条消息到queue,一个queue可以有很多消费者,但是一个消息只能被一个消费者接受,当没有消费者可用时,这个消息会被保存直到有 一个可用的消费者,所以Queue实现了一个可靠的负载均衡。

发布订阅模式

发布者发送到topic的消息,只有订阅了topic的订阅者才会收到消息。topic实现了发布和订阅,当你发布一个消息,所有订阅这个topic的服务都能得到这个消息,所以从1到N个订阅者都能得到这个消息的拷贝。

正文到此结束
本文目录