本文探讨了JMS消息中间件和Kafka部署的差异、权衡和架构。对于基于JMS的消息队列 (MQ) 基础架构和基于Apache Kafka的数据流的比较是一个广泛的话题。本文探讨JMS消息代理和Kafka部署的区别、权衡和架构,以及分析如何在JMS代理(如 IBM MQ 或 RabbitMQ)和开源Kafka或无服务器云服务(如 Confluent Cloud)之间进行选择。
动机:苹果与橘子之战
Kai Waehner在Confluent担任技术布道者,他经常在JavaOne、O'Reilly Software Architecture或ApacheCon等国际会议上发表演讲,为专业期刊撰写文章,分享新技术方面的经验。
Kai几乎每周都需要在客户会议上讨论JMS消息代理和Apache Kafka之间的差异和权衡。他发现时下有大量关于JMS、Kafka的误解,偶尔也会看到一些不当的博客文章和演讲,为此感到恼火,并整理了十个比较准则,目的是解释消息队列和数据流之间的区别,澄清相关API或实施部署的一些常见误解,并提供相应的技术选型思考。
10个比较准则:JMS与Apache Kafka
JMS和Kafka都各自提供一系列产品和云服务, 例如:JMS API的实现(包括开源和商业产品):Apache ActiveMQ、Apache Qpid(使用 AMQP)、IBM MQ(先前是 MQSeries,现在是 WebSphere MQ)、JBoss HornetQ、Oracle AQ、RabbitMQ、TIBCO EMS、TIBCO Cloud Messaging、Solace等等。Apache Kafka产品、云服务和重写(不仅使用开源 Kafka 的有效选项):Confluent、Cloudera、Amazon MSK、Red Hat、Redpanda、Azure Event Hubs 等。
下面是比较JMS消息代理与Apache Kafka及其相关产品/云服务的标准:1.消息代理与数据流平台2.API规范与开源协议实现3.事务处理与负载分析4.推送与拉取消息5.简化、强大和复杂的API6.持久存储与真正解耦7.服务器端数据处理与解耦持续数据流处理8.复杂操作与无服务器云9.Java/JVM与任何编程语言10.单一部署与多区域(包括混合和多云)复制现在逐一探讨这十个比较准则。
1、JMS与Kafka相差甚巨
JMS消息代理提供消息收发功能包括生成和使用消息。Apache Kafka是一个数据流平台,综合了消息传递、存储、数据集成和流处理功能。
首先,在Kai看来,JMS和Apache Kafka的差别相当巨大,甚至可以说二者就不是同一个事物。
JMS API(以及IBM MQ、RabbitMQ 等的实现) JMS(Java 消息服务)是提供通用消息模型的Java应用程序编程接口 (API)。API处理生产者-消费者问题,为了方便软件系统之间的消息发送和接收。因此,JMS消息代理(及实现JMS API)的核心功能是将消息从源应用程序实时得发送到另一个目的地程序。所以需要针对实际使用需求来选择JMS!值得注意的一点是,项目必须使用额外的工具来完成数据集成和高级数据处理任务。 Apache Kafka(开源和供应商,如 Confluent、Cloudera、Red Hat、Amazon等) Apache Kafka是一种用于数据流的开源协议实现。这包括:
- Apache Kafka是分布式消息收发和存储的核心,具有高吞吐量、低延迟、高可用性和安全性。
- Kafka Connect是一个用于将外部源/目标连接到Kafka的集成框架。
- Kafka Streams是一个简单的Java 库,支持在Kafka框架内进行流式应用程序开发。
这种功能组合能够构建端到端数据管道和应用程序,因而相比消息队列而言,Kafka组合的用武之地要更广。
2、 API规范与开源协议实现
JMS是供应商以他们自己的方式实施和扩展的规范。Apache Kafka是底层指定 Kafka协议的开源实现。
在评估对比JMS和Kafka之前,更重要的是澄清以下这些术语:
- 标准API:由行业联盟或其他行业中立(通常是全球性)团体或组织指定标准 API。需要对所有功能进行合规性测试并完成认证才能符合标准。示例:OPC-UA标准
- 事实标准API:源自现有的成功解决方案(开源框架、商业产品或云服务)。示例:Amazon S3(来自单一供应商的所有权),Apache Kafka(来自充满活力的社区的开源)。
- API规范:定义供应商如何实现相关产品的规范文档。对于所有功能的实现,没有完整的合规性测试或完整的认证。导致的结果是一个“标准API”,再各种实现之间没有可移植性。例如:JMS,请注意,为了能够使用JMS的一系列合规性组件,供应商必须向Oracle签署非常繁琐的报告。
替代类型的标准需要权衡取舍。如果您想了解更多信息,请查看过去几年Apache Kafka如何成为数据流的事实标准。
与过去几十年将工作负载放在单个数据中心相比,可移植性和迁移性在混合和多云环境中变得更加重要。
JMS是面向消息的中间件的规范
JMS是目前在Java Community Process下作为JSR 343维护的规范。最新(尚未发布)版本JMS 3.0作为 Jakarta EE 的一部分正在早期开发中,并更名为Jakarta Messaging API。今天,JMS 2.0是流行的消息代理实施中使用的规范(没有人知道JMS 3.0将走向何方)。因此,这里重点介绍JMS 2.0规范以解决现实世界的难题。通常,当人们提及JMS时,他们指的是JMS消息代理实现,而不是JMS API规范。下文会用“JMS消息代理”来替代JMS(即 API),并没有指定JMS实现中已知的特性。 JMS消息代理和JMS可移植性神话
JMS开发规范提供一个通用Java库来访问不同的消息供应商的代理。它用来充当消息代理供应商专有API的包装器,就像JDBC为数据库API提供类似功能一样。然而,这种简单的集成结果并不能实现。因为 将JMS代码从一个供应商的代理迁移到另一个供应商非常复杂 ,原因如下:
- 并非所有JMS功能都是必需的(安全性、队列标签、集群、路由、压缩等等)
- 没有用于传输的JMS规范
- 没有规范来定义如何实现持久性
- 没有规范来定义如何实现容错或高可用性
- 不同供应商对JMS规范的不同理解可能导致相同JMS功能具有潜在的行为差异
- 没有安全规范
- 代理间中没有关于增值功能的规范(例如主题到队列桥接、代理间路由、访问控制列表等)
因此,JMS供应商之间的简单源代码迁移和互操作性就是一个神话!供应商在代理中提供了大量独特的功能(例如:主题到队列的映射、代理路由等),它们为应用程序提供架构功能,但它们是代理功能的一部分,而不是应用程序或JMS的一部分规格。
Apache Kafka是数据流的开源协议实现
Apache Kafka是一种实时数据流处理的可靠且可扩展的实现。该项目是开源的,在Apache 2.0许可下可用,并由一个庞大的社区推动发展。Apache Kafka不是OPC-UA 之类的标准或JMS之类的规范。但是,Kafka至少提供了源代码,参考实现、协议和API定义等。
Kafka已经成为了数据流领域的事实标准。今天,超过100000个组织使用 Apache Kafka;Kafka API也已经成为事件驱动架构和事件流的事实标准。它在所有行业和基础设施中都有用例,包括各种事务处理和分析负载在边缘、混合、多云环境中都有用到。
可能有些人对于Kafka API并不熟悉。这里澄清一下:如前所述,Apache Kafka是分布式数据流平台的一种实现,包括服务器端和客户端以及用于生产和消费事件、配置、安全性、操作等的各种API。Kafka API也是重要的,因为Kafka可重写,如Azure Event Hubs和 Redpanda就使用了它们。
Apache Kafka的可移植性:又一个神话?
Apache Kafka作为开源项目,本身就已经是非常完整的Kafka实现。不少供应商已经使用整个Apache Kafka方案,并围绕它构建更高级的产品。Kafka的迁移非常简单,因为于Kafka而言,不同供应商都采用相同的规范,代码、库和包都是相同的。例如,从Cloudera到Confluent部署或从自我管理的Apache Kafka开源基础架构到无服务器Confluent Cloud的迁移都非常成功。
Kafka API:Kafka的重写Like Azure Event Hubs、Redpanda、Apache Pulsar
随着Kafka在全球的成功,一些供应商和云服务并没有在Apache Kafka实现上构建产品。相反,他们通过Kafka API重新构建了自己的产品。底层实现是特有的(如Azure的云服务事件中心)或开源的(如Apache Pulsar的Kafka桥或Redpanda用C++重写的)。
所以,我们要看供应商到底是集成了整个Apache Kafka项目,还是重写了完整的API。使用Kafka API重写Kafka是一个全新的实现!许多供应商甚至在其支持条款和条件中,完全排除了某些组件或API(例如用于数据整合的Kafka Connect或用于流处理的 Kafka Streams),或者排除了诸如一次性语义或长期存储等关键特性。
目前市面上有各种各样的Kafka产品,比如:Confluent、Cloudera、Red Hat 或Amazon MSK等Kafka供应商,还有Azure Event Hubs、AWS Kinesis、Redpanda或Apache Pulsar等相关技术。如何评估这些呢?首先,应该对需求进行专业测试。如果Kafka-to-XYZ桥接的代码少于一百行,或者从中间件供应商处下载的是Exe的Windows Kafka服务器程序,一定要对上述代码和程序持怀疑态度。闪光的不都是金子。某些框架或供应商还是有华而不实的嫌疑的。比如说,仅仅支持Kafka API、提供完全托管的无服务器Kafka产品,再比如在Kafka 上强推具有不确定性和被怀疑的功能 (FUD)等。例如,Kai就对Pulsar总是试图通过在开源社区中创建大量“不确定性和神话”来变得比Kafka更好而感到恼火。在Kai看来,“不确定性”对供应商来说都是错误的策略。基于这个原因,Kafka的使用率仍在疯狂增长,而Pulsar的百分比增长要慢得多(当然,二者本身的下载量的差距也十分明显)。
3、事务性与分析性工作负载
JMS消息代理仅支持为低容量消息提供事务功能。而Apache Kafka更为强大,它支持低容量和高容量的消息,且支持事务性和分析性工作负载。 JMS:会话和两阶段提交 (XA) 事务 大多数JMS消息代理都很好地支持事务性工作负载。事务处理会话支持单个事务系列。每个事务将一组产生者消息和一组消费者消息组合成一个原子工作单元。两阶段提交事务(XA 事务)在有限的范围内工作。它们适用于与大型机CICS / DB2或Oracle数据库等其他系统整合在一起。但操作较难,并且不能扩展到每秒几笔交易。
需要注意的是,与会话事务不同,JMS 2.0规范并不强制支持XA事务。
Kafka:Exactly-Once Semantics和事务API
Kafka是一个分布式的容错系统,天生具有弹性(如果您正确部署和操作它)。可以确保没有宕机和数据丢失,就像在您最喜欢的数据库、大型机或其他核心平台中一样安全可靠。
甚至更好:Kafka的事务API,即Exactly-Once Semantics (EOS),从Kafka 0.11开始可用。EOS使构建事务工作负载变得更加容易,因为您不再需要处理重复项。Kafka通过事务API支持跨多个分区的原子写入事务。这允许生产者将一批消息发送到多个分区。批处理中的所有消息最终对任何消费者都是可见的,或者对消费者不可见。
Kafka事务的工作方式与JMS事务非常不同。但目标是相同的:每个消费者只接收一次生成的事件。可以在博客文章“使用Apache Kafka的数据流中的分析与事务”中查找更多详细信息。
4、 Push vs. Pull 消息消费
JMS消息代理将消息推送到消费者应用程序。Kafka消费者拉取消息,为独立的消费者应用程序提供真正的解耦和背压处理。
对于像基于JMS的消息代理这样的实时消息系统来说,推送消息似乎是显而易见的选择。但是,基于推送的消息传递在解耦和可扩展性方面存在各种缺点。
JMS希望代理提供背压并实现“预取”功能,但这不是强制性的。如果使用,代理将控制您无法控制的背压。
使用Kafka,消费者可以控制背压。每个Kafka消费者实时、批量或仅按需消费事件——以特定消费者支持和处理数据流的方式。对于许多不灵活和非弹性的环境来说,这是一个巨大的优势。
因此,虽然JMS有某种背压,但如果队列已满,生产者就会停止。在Kafka中,您可以控制消费者的背压。无法使用JMS扩展生产者(因为JMS队列或主题中没有分区)。
JMS消费者可以扩展,但会失去有保证的排序。JMS消息代理中的保证排序仅通过单个生产者、单个消费者和事务起作用。
5、 二者的API复杂度不同
JMS API提供了简单的操作来生成和消耗消息。Apache Kafka有一个更细粒度的API,它带来了额外的功能和复杂性。
JMS供应商在规范下的实现中隐藏了所有很酷的功能。你只得到5%(无控制,由供应商提供的功能)。你需要自己实现剩下的功能。相反,Kafka暴露了一切功能,而大多数开发人员只需要5%。总之,请注意JMS消息代理的构建是为了将消息从数据源发送到一个或多个数据接收器。Kafka是一个数据流平台,提供更多功能、特性、事件模式和处理选项;并且平台规模更大。考虑到这一点,二者的API非常不同并且具有不同的复杂性也就不足为奇了。如果您的用例只需要每秒从A向B发送几条消息,那么JMS是正确的选择并且使用简单!如果您需要任意规模的流数据中心,包括数据整合和数据处理,那只有Kafka。
异步请求-回复与动态数据 JMS开发人员的一个初衷是使用Kafka中的请求-响应功能。请注意,这种设计模式在消息传递系统中与RPC(远程过程调用)不同,消息代理中的请求-回复是一种利用相关ID的异步通信。
从生产者(比如移动应用程序)到消费者(比如数据库)获取事件的异步消息传递是一种非常传统的工作流程。无论是执行发后即忘还是请求回复,数据都将置于静止状态以供进一步处理。JMS支持开箱即用的请求-回复,非常简单。Kafka日志是持久的,带有事件流的动态数据会持续处理数据。Kafka应用程序实时或批量维护和查询状态。对于大多数开发人员和架构师来说,数据流是一种范式转变。这种设计模式非常不同。千万不要尝试使用相同的模式和API在Kafka中重新实现JMS应用程序。这种反模式极可能失败。
请求-响应模式的效率低下可能会导致非常多的延迟,而HTTP或gRPC适用于某些特定的用例。CQRS(命令查询职责隔离)将“请求-响应”替换为流数据的Kafka。但JMS API则无法实现CQRS,因为JMS不提供状态功能并且缺乏事件溯源功能。 请求-响应模式的Kafka示例 对于许多Kafka用例,CQRS是更好的设计模式。尽管如此,请求-响应模式也可以用Kafka来实现,但注意:尝试像在JMS消息代理中那样做(带有临时队列等)最终会宕机Kafka集群(因为它的工作方式不同)。Kafka Spring Boot Kafka模板库有大量的实例,其使用Kafka构建的请求-回复模式。
Kafka模板的Spring文档有很多关于Kafka的请求/回复模式的详细信息。因此,如果使用Spring,那么使用Kafka实现请求/响应模式非常简单。
6、 持久性存储与真正的解耦
JMS消息代理使用存储系统来提供高可用性。Kafka的存储系统更先进,可以实现历史事件的长期存储、背压处理和可重放功能。
Kafka存储远不止JMS的持久性功能
当Kai向经验丰富的JMS开发人员解释Kafka存储系统时,几乎总是得到相同的回应:“我们的JMS消息代理XYZ也有存储。Kafka的好处在哪里?”JMS使用临时存储系统,其中消息仅在被处理之前被持久化。
消息的长期存储和可重放性功能就不是为JMS设计的概念
附加日志、偏移量、排序保证、保留时间、压缩主题等Kafka的核心原则提供了许多超出JMS的持久性保证的额外好处。背压处理、消费者之间的真正解耦、历史事件的可重放性等等是JMS和Kafka之间的巨大差异。翻阅Kafka文档,深入了解Kafka存储系统。Kafka的分层存储,通过在Kafka日志中提供更好的可扩展性和具有成本效益的长期存储,也是值得深究的技术细节。
7、数据处理方式不同
JMS消息代理提供简单的服务器端事件处理,例如基于消息内容的过滤或路由。Kafak消息代理是不够智能的。它的数据处理在解耦的应用程序/微服务中执行。
JMS服务器端过滤和路由
大多数JMS消息代理都为服务器端事件处理提供了一些功能。这些功能对于某些工作负载很方便!请注意,服务器端处理通常是有代价的。例如:
- JMS预过滤可伸缩性问题:代理必须处理很多事情。这可以用隐藏的方式宕掉JMS服务。
- JMS选择器(路由)性能问题:它会消耗掉集群40-50% 的性能
当然,如果可以容忍这些缺点,那么它也不失为一个很棒的功能。
Kafka:弱管道和强终端
Kafka 有意不提供服务器端处理,这处理发生在智能端点。这是一个非常著名的设计模式:弱管道和强终端
缺点是您需要分别在应用程序/微服务/数据产品中实现相关逻辑。这在无服务器环境中不是大问题。它在自我管理的环境中变得更加复杂。
然而,这种架构一个非常大的好处在于:应用程序/技术/编程语言之间可以做到真正解耦,用于构建业务逻辑和基础设施操作的业务单元之间的关注点分离,以及更好的可扩展性和弹性。
Kafka未来是否会有一定的服务器端处理能力?Kai认为当然会有。特别是对于少量工作负载,性能和可扩展性的影响都应该是可以接受的!不过,风险在于开发者是否会滥用这些功能。未来将会证明Kafka是否具有此项功能。
复杂操作与无服务器云
可扩展JMS消息代理或Kafka集群的自我管理操作很复杂。无服务器产品(应该)担负起运营重担。
不管是JMS还是Kafka,操作集群都很复杂
一个基本的JMS消息代理相对容易操作(包括主动/被动设置)。但是,这限制了可扩展性和可用性。JMS API旨在与单个代理或主动/被动通信以实现高可用性。这个概念涵盖了应用领域。对于 JMS 消息代理来说操作集群是非常复杂。来自商业供应商的更高级的消息代理集群更强大,但是也更难操作。Kafka是一个强大的分布式系统。
完全托管的无服务器云救援
在Kafka中,这情况就不同了。由于Kafka是一个可扩展的分布式系统,云提供商可以构建云原生无服务器产品。构建这样一个完全托管的基础设施仍然非常困难。因此,评估相关云产品,而不仅仅是看其外在的营销口号!
每个Kafka云服务都标榜为“完全托管”或“无服务器”,但大多数不是。一些云供应商甚至从他们的Kafka云产品中排除了对Kafka的支持。疯狂,但够真实。所以检查条款和相关条件可以作为评估的一部分。
9、 Java/JVM 与任何编程语言
JMS专注于JVM编程语言的Java生态系统。而Kafka独立于编程语言。
正如名称JMS(及Java 消息服务)所说:JMS是专门为Java编写的。一些代理供应商支持他们自己的API 和客户端。这些是该供应商专有的。我过去见过的几乎所有重要的JMS项目都使用Java代码。
Apache Kafka也只提供了一个Java客户端。但是供应商和社区为几乎所有编程语言提供了其他语言绑定,以及用于HTTP通信的REST API,用于生成/消费来自Kafka的事件。
Kafka后端的真正解耦使不同的客户端应用程序能够相互交流,无论使用哪种编程语言。这种灵活性允许构建适当的领域驱动设计 (DDD),其中微服务架构利用Kafka作为中枢神经系统。
10、 单 JMS 部署与多区域(包括混合云和多云)Kafka 复制
JMS API是应用程序和代理之间通信的客户端规范。Kafka是一个分布式系统,可为混合云和多云用例提供各种架构。
JMS是客户端规范,而多数据中心复制是代理功能。这里不再深入讲解,简单地说:JMS消息代理不是为跨区域、洲际或混合/多云环境的复制场景而构建的。
Apache Kafka的多集群和跨数据中心部署已成为常态而非例外。各种场景需要多集群Kafka解决方案。可以根据实际情况进行考虑具体要求和权衡取舍。诸如MirrorMaker(开源)或Confluent Cluster Linking(商业)等Kafka技术都支持灾难恢复、聚合分析、云迁移、任务关键延伸部署和全域Kafka部署等用例。
11、JMS 和 Kafka对比总结
以上这10个比较维度,表明JMS和Kafka是有着非常大差异的。虽然两者也有重叠的领域(例如,消息传递、实时、关键任务),但它们使用不同的技术能力、特性和架构来支持其他功能用例。
简而言之,使用JMS代理进行从A到B的简单和低容量的消息传递。而Kafka通常是许多数据源和数据接收器之间的实时数据中心(许多人称其为企业架构的中心实时组织系统)。
Kafka在任意规模的数据集成和数据处理能力、真正的解耦、事件可重放性是与基于JMS的MQ系统的主要区别。 但是,尤其是在无服务器云中,不要担心Kafka太强大(太复杂)。无服务器Kafka项目通常以非常低的容量、非常便宜的方式进行,没有运营负担。然后它可以随着您不断增长的业务而扩展,而无需重新构建应用程序。
12、 选择与评估要考虑哪些?
了解基于JMS的消息代理和由Apache Kafka提供支持的数据流之间的技术差异。评估这两个选项以找到解决问题的正确工具。在消息传递或数据流中,进行更详细的评估。每个消息代理都是不同的,即使它们都符合JMS。同样,所有Kafka产品和云服务在功能、支持和成本方面都不同。
所以开发者应针对实际需求和二者的用例及限制来进行适当的选择。
译者介绍
田小保,51CTO社区编辑,资深云计算架构师,互联网老兵,拥有15年以上互联网软件开发和架构经验,具有多年的项目管理经验。熟悉云计算、大数据等的互联网开发技术。
原文链接:
https://dzone.com/articles/comparison-jms-message-queue-vs-apache-kafka?fromrel=true