作者简介
Gavin,程序员、软件架构师、企业架构师,关注智能制造。
本文是专栏《智能制造系统架构》中的文章,其它文章请参阅入坑智能制造系统架构。
消息队列是分布式系统中重要的组件,也是企业不同应用系统集成的关键中间件。目前常用的Kafka、RabbitMQ、ActiveMQ、ZeroMQ、RocketMQ等都是属于消息队列。而在企业IT架构中,还会使用到服务总线、流处理平台等技术概念或组件。
本文为你梳理一下消息队列是做什么的?何时使用消息队列?企业服务总线和流处理平台和它又是什么关系?希望对你有所帮助。
目录
什么是队列
什么是消息队列
消息队列的优势
消息模型——如何发布和获取消息
Point-to-Point(PTP)模型
Publisher/Subscriber (Pub/Sub) 模型
何时使用消息队列
服务总线
流处理平台——Kafka
参考资料
队列是一种先进先出的数据结构,特殊之处在于它只允许在队列的前端(front)进行删除操作,而在队列的后端(rear)进行插入操作。
消息队列就是一个队列结构的中间件,也就是说消息放入这个中间件之后就可以直接返回,并不需要系统立即处理,而另外会有一个程序读取这些数据,并按顺序进行逐次处理。
消息队列的核心功能就是消息传递。但由于其异步性和消息存储的特定,使消息队列具备如下优势:
1. 解耦
消息队列在处理过程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口。这允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。
2. 冗余
有时在处理数据的时候处理过程会失败。除非数据被持久化,否则将永远丢失。消息队列把数据进行持久化直到它们已经被完全处理,通过这一方式规避了数据丢失风险。在被许多消息队列所采用的"插入-获取-删除"范式中,在把一个消息从队列中删除之前,需要你的处理过程明确的指出该消息已经被处理完毕,确保你的数据被安全的保存直到你使用完毕。
3. 扩展性
因为消息队列解耦了你的处理过程,所以增大消息入队和处理的频率是很容易的;只要另外增加处理过程即可。不需要改变代码、不需要调节参数。扩展就像调大电力按钮一样简单。
4. 灵活性 & 峰值处理能力
在访问量剧增的情况下,你的应用仍然需要继续发挥作用,但是这样的突发流量并不常见;如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住增长的访问压力,而不是因为超出负荷的请求而完全崩溃。
5. 可恢复性
当体系的一部分组件失效,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。而这种允许重试或者延后处理请求的能力通常是造就一个略感不便的用户和一个沮丧透顶的用户之间的区别。
6. 送达保证
消息队列提供的冗余机制保证了消息能被实际的处理,只要一个进程读取了该队列即可。
7.排序保证
在许多情况下,数据处理的顺序都很重要。消息队列本来就是排序的,并且能保证数据会按照特定的顺序来处理。
8.缓冲
在任何重要的系统中,都会有需要不同的处理时间的元素。例如,加载一张图片比应用过滤器花费更少的时间。消息队列通过一个缓冲层来帮助任务最高效率的执行--写入队列的处理会尽可能的快速,而不受从队列读的预备处理的约束。该缓冲有助于控制和优化数据流经过系统的速度。
9. 理解数据流
在一个分布式系统里,要得到一个关于用户操作会用多长时间及其原因的总体印象,是个巨大的挑战。消息系列通过消息被处理的频率,来方便的辅助确定那些表现不佳的处理过程或领域,这些地方的数据流都不够优化。
10. 异步通信
很多时候,你不想也不需要立即处理消息。消息队列提供了异步处理机制,允许你把一个消息放入队列,但并不立即处理它。你想向队列中放入多少消息就放多少,然后在你乐意的时候再去处理它们。
JMS(Java Message Service,Java消息服务)API是一个消息服务的标准/规范,允许应用程序组件基于JavaEE平台创建、发送、接收和读取消息。在JMS标准中,有两种消息模型:P2P(Point to Point),Publish/Subscribe(Pub/Sub)。
在P2P模型中,每个消息只有一个消费者(即一旦被消费,消息就不再在消息队列中),队列保留着消息,直到它们被消费或超时。发送者和接收者之间在时间上没有依赖性,也就是说当发送者发送了消息之后,不管接收者有没有正在运行,它不会影响到消息被发送到队列。接收者在成功接收消息之后需向队列应答成功如果你希望发送的每个消息都应该被成功处理的话,那么你需要P2P模型
在Pub/Sub模型中包含如下概念:主题(Topic)、发布者(Publisher)、订阅者(Subscriber)。客户端将消息发送到主题。多个发布者将消息发送到Topic,系统将这些消息传递给多个订阅者。
每个消息可以有多个消费者。发布者和订阅者之间有时间上的依赖性。针对某个主题(Topic)的订阅者,它必须创建一个订阅之后,才能消费发布者的消息,而且,为了消费消息,订阅者必须保持运行的状态。当然,为了缓和这种严格的时间相关性,JMS允许订阅者创建一个可持久化的订阅。这样,即使订阅者没有被激活(运行),它也能接收到发布者的消息。如果你希望发送的消息可以不被做任何处理、或者被一个消费者处理、或者可以被多个消费者处理的话,那么可以采用Pub/Sub模型。
消息队列是软件系统作信息传递和系统集成的主要手段,同时相对于使用消息队列发送消息而言,还有另外一种更加普遍使用的集成技术,就是API。两者都具有广泛的应用,所以在实际架构设计中,经常要考虑的问题是什么时候使用API,什么时候使用消息队列。下表列出两者主要的区别:
特征 |
API | 消息队列 |
---|---|---|
交互特性 |
HTTP是同步的。每个请求消息都会有相应的反馈,从而实现了请求/响应机制。 |
消息是异步的。实现发布/订阅机制,在该机制下应用系统可以将消息注册到定义好的主题上,然后将消息发布给所有的订阅者。 |
应用调用 |
API 普遍存在,几乎所有IT基础设施都会支持HTTP访问,并且大多数开发语言也会内置支持HTTP。 |
需要简单的应用开发工作。消息可以帮助你简化避免消息丢失的工作,使你能够能加专注于业务。 |
耦合性 |
会有一点耦合。因为信息流会直接从请求方发送到服务提供方。 |
完全解耦。消息队列扮演了一个临时缓存库的角色。这样即使接收消息的应用或服务器崩溃了,或者过于繁忙无法处理请求,消息可以在消息队列中等待知道服务方可以处理为止。 |
如何判断什么时候该使用API,什么时候该使用消息呢?举个例子:
假设一个零售商开放他的产品清单。通过开放这个产品清单,合作厂商可以快速定位到自己的产品。产品清单中的数据是只读的,所以用户可以重复的请求访问。这种场景下,REST API使用简单并且同步,更适合这个场景。
另一个场景,假设一个医院要在治疗病人之后更新病人的病历。病历信息对于医院和病人来讲都是非常关键的信息,为了保证信息在传输过程中不会丢失,此时采用消息更加合适。
最后一个场景。假设一个零售商搭建一个应用允许合作厂商访问他的产品清单并下订单。这种情况下,可以同时使用API和消息。在查询产品清单时,可以使用API。而在下订单时,为了避免消息丢失和处理峰值流量,可以使用消息队列。
消息总线可以理解成全局的消息通道。所以相对消息队列而言,他的不同之处在于全局性和共享性。所以,消息总线会包含三部分:通用数据模型、通用指令集和消息队列。跟随SOA(Service Oriented Architecture,面向服务架构)的概念,信息系统的总线通常叫服务总线,企业层的总线称之为企业服务总线(ESB)。企业服务总线可以看作是一种模式,在这种模式下定义了一个集中式的消息中间件实现各种后端系统的集成(包括数据模型转换、连接、路由和编排),从而实现些集成服务可以在构建新应用时复用。
在SOA中,IT架构被分成组件层、Web服务层、业务流程层等。组件层包括各种应用系统,它们通常是技术相关的具体实现,各种具体的分布式组件技术(CORBA、COM/DCOM、J2EE)都可以用于实现组件层的应用组件。通常复杂的IT环境中的组件层都同时使用了多种分布式组件技术,而不同实现技术之间的互联性障碍给应用集成带来了极大的困难,进而形成了一个个信息孤岛。SOA引入了Web服务层来解决此种情况下的应用集成问题。Web服务是独立于各种分布式组件技术的,它使用标准的基于XML的服务描述语言(Web Service Description Language,WSDL)来定义和封装离散的业务功能,各种支持Web服务的分布式组件技术能够将其上的业务组件发布成Web服务并产生相应的WSDL文档,并且只需要依据WSDL描述的信息就能够调用Web服务,即WSDL所描述的业务功能。在SOA中,需要进入系统集成环节的业务组件都被映射为Web服务,形成了Web服务层。业务流程层则处于Web服务层之上,通过对Web服务的流程编排来实现商业流程。业务流程层通过Web服务层能够调用到基于各种分布式组件技术实现的业务组件,实现了复杂IT系统环境的应用集成。
作为SOA基础架构的关键部分,ESB的功能主要体现在通信、服务交互、应用集成、服务质量、安全性以及管理和监控等方面。在通信方面,ESB能够支持消息路由/寻址,支持多种通信技术、通信协议(如JMS、HTTP),支持发布/订阅的通信模式,能够处理请求/响应、同步以及异步的消息传递方式,并且要求以可靠的方式传递消息。
常见的ESB产品包括:IBM的WebSphere ESB,Microsoft 基于BizTalk的ESB产品,JBOSS SOA Platform等。
需要强调的是,消息总线或企业服务总线的目的是为了系统集成和服务共享。因此,当使用消息总线的时候,所有的服务或者应用必须共享相同的数据类型,指令集以及相同的通信协议,并且在消息总线中,会最大量消息转换和编排的工作。而相对而言,消息队列的目的是信息传输,因此并不限制是否类型一致。
市面上的消息队列产品有很多,比如ActiveMQ、RabbitMQ 、Kafka 、RocketMQ ,还有 ZeroMQ ,连 redis 这样的 NoSQL 数据库也支持 MQ 功能。但其中影响力最大的应该还是Kafka。而从Kafka给自己的定义可以看出,Kafka不只是消息队列,而是分布式的流处理平台。
什么是流处理平台呢?流处理是一种重要的大数据处理手段,其主要特点是其处理的数据是源源不断且实时到来的。分布式流处理是一种面向动态数据的细粒度处理模式,基于分布式内存,对不断产生的动态数据进行处理。其对数据处理的快速,高效,低延迟等特性,在大数据处理中发挥越来越重要的作用。流处理技术有很多技术选型,更多信息可以参考“Apache 的流处理技术概述”。仅从Kafka的角度看流处理平台和消息队列的区别,Kafka作为流处理平台具有以下三种特性:
但与基于队列和交换的RabbitMQ不同,Kafka的存储层是使用分区的事务日志实现的。Kafka还提供用于实时处理流的Streams API和可轻松与各种数据源集成的Connector API。Kafka没有“执行队列”的概念。相反,Kafka将记录的集合存储在称为主题(Topic)的类别中。对于每个主题,Kafka维护消息的分区日志。每个分区都是一个有序的,不可变的记录序列,在该记录中连续附加消息。因此Kafka的实现十分适合“Publisher/Subscriber (Pub/Sub) 模型”,但不适合“Point-to-Point(PTP)模型”。因此Kafka的定位并非消息队列或消息总线,而是流处理平台。
因此,流处理平台和消息队列或消息总线最大的区别就是在消息队列功能基础上,流处理平台更加关注对流数据分析的支持。