一 、 概 念
首先问什么是消息?
“消息”是在两台计算机间传送的数据单位; 其中消息可以为数字、字符、或者一串字符、实体对象。
什么是队列?
队列:在数据结构中的特点为先进先出,可以理解为生活中的排队形式。
什么是消息队列?
但从名字中可以看出,为存放消息的一种队列
,可以简单理解为:把要传输的数据放在队列中。而消息队列是分布式系统中重要的组件,可以在 分布式环境 下提供应用解耦、弹性伸缩、冗余存储、流量削峰、异步通信、数据同步
对于消息队列来说,我们一般会简称它为MQ,主要的就是解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构。把数据放到消息队列叫做生产者,而从消息队列里边取数据叫做消费者
举 例:
当你在某团中下单时,正好你又有自己事要去忙,但是你又担心等下小哥突然很快的到来,需要你去接收一下;
正在你忙着忙着的时候,突然接到小哥的电话:
小哥:“你是xx吗?你的快递到了,你可以马上过来拿一下吧!”。
我:“额… 那个我现在还忙,要不你等我一会儿?“。
小哥:“这可不行啊,我还有好多的单子需要去派送呢,要是其他的单子晚送到,肯定要被投诉了”。
于是两个人僵持了很久……
最后小哥说,要不我帮你放到楼下便利店吧,等你忙完了可以过来拿,这回这种局面才解决~
而如果没有便利店或者其他的可以存放的东西的话,则小哥和我情景就应该如下:
思考:
1.当小哥打电话来的时候,叫我过去,当时我正在忙的时候,如果这个时候如果过去了,那么可能就耽误到自己的事情,万一很重要呢?
2.但是如果你不过去,而且小哥自己又有苦衷,他也不可能一直的等你。
3.如果没有存放点,那我点的东西不要了?
这个时候就可以看出消息队列的重要性了,就相当于便利店一样,可以作为存放数据,不耽误该服务的工作。
二 、应用场景:
就以上面的例子为说明:
1、 异步
当这位小哥打电话的时候,如果没有存放点,且直到我拿走他上手我的东西之后,他才可能能去送其他人的。当有了存放点的时候,这位小哥就可以将我的东西放在该存放点了,接下来他就可以干其他的活儿去了,不需要等待你到来而一直而处于等待状态,直接大大的提高了工作的效率。
消息发送者 可以发送一个消息而无须等待响应。消息发送者 将消息发送到一条 虚拟的通道(主题 或 队列)上,消息接收者 则 订阅 或是 监听 该通道。一条信息可能最终转发给 一个或多个 消息接收者,这些接收者都无需对 消息发送者 做出 同步回应。整个过程都是 异步的。
2、 解耦
小哥手上有很多快递需要送,而他每次都需要先电话一一确认收货人是否有空、哪个时间段有空,总是要询问一些情况,然后再确定好方案。那么这样的话就完全依赖收货人这边了啊!那么如果快递量大的时候,那这小哥估计的忙疯了……如果有了存放点的话,小哥只需要将同一个小区的快递放在同一个点,然后通知收货人来取货就可以了,这时候小哥和收货人就真正实现了解耦!
系统之间不是 强耦合的,消息接受者 可以随意增加,而不需要修改 消息发送者的代码。消息发送者 的成功不依赖 消息接受者(比如:有些银行接口不稳定,但调用方并不需要依赖这些接口)。
不强依赖 于非本系统的核心流程,对于 非核心流程,可以放到消息队列中让 消息消费者 去按需消费,而 不影响核心主流程。
3、 削峰
假设双十一我买了不同店里的各种商品,而恰巧这些店发货的快递都不一样,有中通、圆通、申通、各种通等……更巧的是他们都同时到货了!这时中通的小哥打来电话叫我去北门取快递、圆通小哥叫我去南门、申通小哥叫我去东门。我一时手忙脚乱……
打平高峰期的流量,消费端可以以自己的速度处理,同时也无需在高峰期增加太多资源,提高资源利用率
三、消息队列通信的模式
1、发布订阅模式
发布订阅模型(Pub/Sub) 使用主题(Topic)作为消息通信载体,类似于广播模式。
发布者发布一条消息以后,该消息通过主题传递给所有的订阅者。在一条消息广播之后再订阅的用户则是收不到该条消息的。
如上图所示,发布订阅模式是一个基于消息送的消息传送模型,改模型可以有多种不同的订阅者。
生产者将消息放入消息队列后,队列会将消息推送给订阅过该类消息的消费者(类似微信公众号)。由于是消费者被动接收推送,所以无需感知消息队列是否有待消费的消息!但是consumer1、consumer2、consumer3由于机器性能不一样,所以处理消息的能力也会不一样,但消息队列却无法感知消费者消费的速度!所以推送的速度成了发布订阅模模式的一个问题!
假设三个消费者处理速度分别是8M/s、5M/s、2M/s,如果队列推送的速度为5M/s,则consumer3无法承受!如果队列推送的速度为2M/s,则consumer1、consumer2会出现资源的极大浪费!
2、点对点模式
使用队列(Queue)作为消息通信载体;满足生产者与消费者模式,一条消息只能被一个消费者使用,未被消费的消息在队列中保留直到被消费或超时。
比如:我们生产者发送100条消息的话,两个消费者来消费一般情况下两个消费者会按照消息发送的顺序各自消费一半。
如上图所示,点对点模式通常是基于拉取或者轮询的消息传送模型,这个模型的特点是发送到队列的消息被一个且只有一个消费者进行处理。生产者将消息放入消息队列后,由消费者主动的去拉取消息进行消费。点对点模型的的优点是消费者拉取消息的频率可以由自己控制。但是消息队列是否有消息需要消费,在消费者端无法感知,所以在消费者端需要额外的线程去监控。
四、消息队列问题
消息队列在实际的应用场景还是很多,但是同时也是有需要去考虑的东西
1 . 数据丢失问题
我们将数据写到消息队列上,系统B和C还没来得及取消息队列的数据,就挂掉了。如果没有做任何的措施,我们的数据就丢了。
学过Redis的都知道,Redis可以将数据持久化磁盘上,万一Redis挂了,还能从磁盘从将数据恢复过来。同样地,消息队列中的数据也需要存在别的地方,这样才尽可能减少数据的丢失。
那存在哪呢?
磁盘?
数据库?
Redis?
分布式文件系统?
同步存储还是异步存储?
2、消费者如何得到数据
消费者怎么从消息队列里边得到数据?有两种办法:
-生产者将数据放到消息队列中,消息队列有数据了,主动叫消费者去拿(俗称push)
-消费者不断去轮询消息队列,看看有没有新的数据,如果有就消费(俗称pull)
3. 高可用
无论是我们使用消息队列来做解耦、异步还是削峰,消息队列肯定不能是单机的。试着想一下,如果是单机的消息队列,万一这台机器挂了,那我们整个系统几乎就是不可用了。
五、 消息队列中间件比较