笔者早年整理的一篇文章,今再回忆一番 ????????????
1. 概述
MQ:即Message Queue,消息队列;消息队列已经逐渐成为系统间通信的核心手段。它具有 低耦合、可靠投递、广播、流量控制、最终一致性 等一系列功能,成为 异步RPC的主要手段之一。当今市面上有很多主流的消息中间件,如老牌的ActiveMQ、RabbitMQ,炙手可热的Kafka,阿里巴巴自主开发的RocketMQ等。
2. 消息中间件的组成
- Broker: 消息代理,即消息中转的中间件,提供消息核心服务,如 RabbitMQ就是一种Broker。
- Producer: 消息生产者,业务的发起方,负责生产消息发布到Broker中 ;
- Consumer: 消息消费者,业务的处理方,负责从Broker获取消息并进行业务逻辑处理 ;
- Queue: 消息队列,图中红色部分。PTP模式下,生产者向特定的Queue发送消息,消费者订阅特定的Queue完成指定消息的接收并消费该消息 ;
-
Message: 消息体,根据不同通信协议【如:AMQP协议】定义的固定格式进行编码的 数据包,来 封装业务数据,实现消息的传输 。
3. 消息中间件模式分类
-
点对点模式(即PTP模式): 使用Queue作为通信载体
mark:
消息生产者生产消息发送到queue中,然后消息消费者从queue中拉取并且消费消息。消息被消费以后,queue中不再存储【会delete掉已消费的消息】,所以消费者不可能消费到已经被消费的消息。 Queue支持存在多个消费者,但是 对一个消息而言,只会有一个消费者可以消费 。
-
发布/订阅: 使用Topic作为通信载体
mark:
1) 消息生产者将消息发布到Topic中,同时有多个消息消费者(订阅者)消费该消息。和点对点方式不同,发布到Topic的 消息会被所有订阅者消费 。
2) Queue实现了负载均衡【这一点在RabbitMQ的 Fair-dispatch 方式中体现出来】,将producer生产的消息发送到消息队列中,由多个消费者消费。但一个消息只能被一个消费者消费,当没有消费者可用时,这个消息会被保存直到有一个可用的消费者。
3) Topic实现了发布和订阅,当你发布一个消息,所有订阅这个topic的服务都能得到这个消息,所以从1到N个订阅者都能得到一个消息的拷贝。
-
其他模式: 如 路由模式、通配符模式等 ;
4. 消息中间件的优势
-
系统解耦: 交互系统之间没有直接的调用关系,只是通过消息传输,故系统侵入性不强,耦合度低。
-
提高系统响应时间: 例如原来的一套逻辑,完成支付可能涉及先修改订单状态、计算会员积分、通知物流配送几个逻辑才能完成;通过MQ架构设计,就可将紧急重要(需要立刻响应)的业务放到该调用方法中,响应要求不高的使用消息队列,放到MQ队列中,供消费者处理。
-
为大数据处理架构提供服务: 通过消息作为整合,大数据的背景下,消息队列还与实时处理架构整合,为数据处理提供性能支持。
-
Java消息服务——JMS: Java消息服务(Java Message Service,JMS)应用程序接口是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
5. 消息中间件应用场景
5.1 异步通信
有些业务不想也不需要立即处理消息,比如双十一期间用户的【下单 + 结算 + 订单落地 + 消息通知等服务,为了提高响应时间,订单落地不需要立即处理】。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它 。想向队列中放入多少消息就放多少【跟队列所在服务器的内存有关】,然后在需要的时候再去处理它们 ;
5.2 系统解耦
降低工程间的强依赖程度,针对异构系统进行适配。在项目启动之初来预测将来项目会碰到什么需求,是极其困难的。通过消息系统在处理过程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口,当应用发生变化时,可以独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束 ;
5.3 冗余【数据一致性】
有些情况下,处理数据的过程会失败。除非数据被持久化,否则将造成丢失。消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。许多消息队列所采用的”插入-获取-删除”范式中,在把一个消息从队列中删除之前,需要你的处理系统明确的指出该消息已经被处理完毕,从而确保你的数据被安全的保存直到你使用完毕 ;
5.4 扩展性
因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。不需要改变代码、不需要调节参数。便于分布式扩容 ;
5.5 过载保护【削峰】
在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量无法提取预知;如果以为了能处理这类瞬间峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃 ;
举个栗子:以订单系统和结算系统场景为例,如果订单系统通过RPC框架来调用结算系统,在有高峰促销的情况下生成订单的量会非常大,而且由于生成订单的速度也非常快,这样势必会给结算系统造成系统压力,服务器利用率则会偏高,但在不是高峰的时间点订单量比较小,结算系统的服务器利用率则会偏低。对于结算系统来说就会出现上面这样的高峰波谷现象图。
那么如果通过MQ的方式,将订单存储到MQ队列中,消费端通过拉取的方式,并且拉去速度有消费端来控制,则就可以控制流量趋于平稳。这样对于结算系统来讲,就达到了削峰填谷的目的。或者说起到了流控的目标 。
5.6 可恢复性
系统的一部分组件失效时,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理 ;
5.7 顺序保证
在大多使用场景下,数据处理的顺序都很重要。大部分消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理 ;
5.8 缓冲
在任何重要的系统中,都会有需要不同的处理时间的元素。消息队列通过一个缓冲层来帮助任务最高效率的执行,该缓冲有助于控制和优化数据流经过系统的速度。以调节系统响应时间 ;
5.9 数据流处理
分布式系统产生的海量数据流,如:业务日志、监控数据、用户行为等,针对这些数据流进行实时或批量采集汇总,然后进行大数据分析是当前互联网的必备技术,通过消息队列完成此类数据收集是最好的选择 。
未完待续 …