定义
消息队列(MQ)是指利用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成。
个人理解就像一个存储消息的数据库,类似图床这样,为了解决平台主体的负载问题,将压力分担到其它系统
消息队列的组成
- Broker
作为server提供核心服务 - Producer
消息生产者,业务的发起方,负责生产消息传输给broker - Consumer
消息消费者,业务的处理方,负责从broker获取消息并进行业务逻辑处理。 - Topic
主题,发布订阅模式下的消息统一汇集地,不同生产者向topic发送消息,由MQ服务器分发到不同的订阅者,实现消息的广播。 - Queue
队列,PTP模式下,特定生产者向特定queue发送消息,消费者订阅特定的queue完成指定消息的接收。 - Message
消息体,根据不同通信协议定义的固定格式进行编码的数据包,来封装业务数据,实现消息的传输。
消息队列特点
1、先进先出:消息队列的顺序在入队的时候就基本已经确定了,一般是不需人工干预的。
2、发布订阅:发布订阅是一种很高效的处理方式,如果不发生阻塞,基本可以当成是同步操作。
3、持久化:持久化确保消息队列的使用不只是一个部分场景的辅助工具,而是让消息队列能像数据库一样存储核心的数据。
4、分布式:在现在大流量、大数据的使用场景下,支持分布式的部署,才能被广泛使用。消息队列的定位就是一个高性能的中间件。
消息队列模式分类
- PTP模式,点对点
通过queue实现一个队列可以对应多个消费者,一条消息只能被一个消费者取用,消费者不可能消费到已经被消费的消息 - 发布/订阅(Pub/Sub)
消息生产者(发布)将消息发布到topic中,同时有多个消息消费者(订阅)消费该消息。和点对点方式不同,发布到topic的消息会被所有订阅者消费。
queue实现了负载均衡,将producer生产的消息发送到消息队列中,由多个消费者消费。但一个消息只能被一个消费者接受,当没有消费者可用时,这个消息会被保存直到有一个可用的消费者。
topic实现了发布和订阅,当你发布一个消息,所有订阅这个topic的服务都能得到这个消息,所以从1到N个订阅者都能得到一个消息的拷贝。
消息中间件的优势
- 解耦
交互的系统之间没有直接的调用,而是通过中间载体传递消息,系统侵入性不强,耦合度低 - 提高系统响应时间
例如原来的一套逻辑,完成支付可能涉及先修改订单状态、计算会员积分、通知物流配送几个逻辑才能完成;通过MQ架构设计,就可将紧急重要(需要立刻响应)的业务放到该调用方法中,响应要求不高的使用消息队列,放到MQ队列中,供消费者处理。 - 为大数据架构提供服务
通过消息作为整合,大数据的背景下,消息队列还与实时处理架构整合,为数据处理提供性能支持。 - java消息服务 JMS
Java消息服务(Java Message Service,JMS)应用程序接口是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
JMS中的P2P和Pub/Sub消息模式:点对点(point to point, queue)与发布订阅(publish/subscribe,topic)最初是由JMS定义的。这两种模式主要区别或解决的问题就是发送到队列的消息能否重复消费(多订阅)。
消息中间件的应用场景
以订单系统为例

1.异步

我们将本来在系统中进行一套流程的操作,即在订单系统调用短信系统等的接口,这样需要所有操作串行执行,数据全部更新完成后才可以给出响应,当我们使用消息中间件集群,就可以将订单支付消息分发给其他系统,这样短信,卡券,库存的业务逻辑同时运行,就可以达到异步,提高响应速度
2.解耦
降低工程间的强依赖程度,针对异构系统进行适配。在项目启动之初来预测将来项目会碰到什么需求,是极其困难的。通过消息系统在处理过程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口,当应用发生变化时,可以独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。
在用户完成订单支付后,订单系统需通知第三方物流仓储系统去完成商品的出库,一般情况下订单系统会调用物流系统的接口,物流系统执行一堆代码逻辑和数据库操作后,将执行接口返回给订单系统,正常情况下,该操作没有什么问题。
但是如果某天物流系统挂了,或是因为某些原因接口运行了几秒才执行完毕,那么订单系统收不到接口返回成功的消息,就无法告知用户订单完成,对于用户来说,是非常差的体验。因此,我们在开发过程中,并不能完全地相信第三方系统,要尽量做到系统间的解耦。
因此,消息中间件被用来实现系统间的解耦,订单系统发送消息到消息中间件集群,消息中间件集群将消息发送到第三方物流系统,订单系统此时并不关心物流系统的执行情况,直接返回订单成功的消息,从而实现系统间的解耦,也避免了订单系统的性能抖动。如图所示。
3.削峰
控制接收数据的最大值,只要这么多,多了拒绝
用于高并发场景,进行削峰。
流量削峰在秒杀系统中应用非常广泛。如果在秒杀活动中每秒上万的请求全部落到数据库,那么必将会导致数据库挂掉,从而导致订单系统崩溃。引入消息中间件后,将用户的请求写入消息队列,如果消息队列的长度超过最大值,那么直接抛弃用户的请求并返回商品秒杀结束的信息给用户。消息中间件集群中积攒的几万条消息可被订单系统慢慢的消费处理掉。瞬间上万并发的压力由消息中间件来抗,订单系统只需要从消息中间件中慢慢拉取消息进行消费,不会对数据库造成影响。
4.冗余
有些情况下,处理数据的过程会失败。除非数据被持久化,否则将造成丢失。消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采用的”插入-获取-删除”范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕。
5 .扩展性
因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。不需要改变代码、不需要调节参数。便于分布式扩容。
6 .过载保护
在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量无法提取预知;如果以为了能处理这类瞬间峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。
7 .可恢复性
系统的一部分组件失效时,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。
8 .顺序保证
在大多使用场景下,数据处理的顺序都很重要。大部分消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。
9 .缓冲
在任何重要的系统中,都会有需要不同的处理时间的元素。消息队列通过一个缓冲层来帮助任务最高效率的执行,该缓冲有助于控制和优化数据流经过系统的速度。以调节系统响应时间。
10. 数据流处理
分布式系统产生的海量数据流,如:业务日志、监控数据、用户行为等,针对这些数据流进行实时或批量采集汇总,然后进行大数据分析是当前互联网的必备技术,通过消息队列完成此类数据收集是最好的选择。
消息中间件常用协议
1. AMQP协议
AMQP即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同开发语言等条件的限制。
优点:可靠、通用
2 .MQTT协议
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分。该协议支持所有平台,几乎可以把所有联网物品和外部连接起来,被用来当做传感器和致动器(比如通过Twitter让房屋联网)的通信协议。
优点:格式简洁、占用带宽小、移动端通信、PUSH、嵌入式系统
3 .STOMP协议
STOMP(Streaming Text Orientated Message Protocol)是流文本定向消息协议,是一种为MOM(Message Oriented Middleware,面向消息的中间件)设计的简单文本协议。STOMP提供一个可互操作的连接格式,允许客户端与任意STOMP消息代理(Broker)进行交互。
优点:命令模式(非topic\queue模式)
4 .XMPP协议
XMPP(可扩展消息处理现场协议,Extensible Messaging and Presence Protocol)是基于可扩展标记语言(XML)的协议,多用于即时消息(IM)以及在线现场探测。适用于服务器之间的准即时操作。核心是基于XML流传输,这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息,即使其操作系统和浏览器不同。
优点:通用公开、兼容性强、可扩展、安全性高,但XML编码格式占用带宽大
5. 其他基于TCP/IP自定义的协议
有些特殊框架(如:redis、kafka、zeroMq等)根据自身需要未严格遵循MQ规范,而是基于TCP\IP自行封装了一套协议,通过网络socket接口进行传输,实现了MQ的功能。
常用消息队列比较



