Kafka
Apache Kafka实现了一个经典的分布式系统。为了处理一个分区的数据,Kafka将整个分区数据存储在每个节点(即Broker)中,该节点负责计算和存储。一个分区可以有多个副本,相应的副本存储在分区leader和in-sync副本(ISR)中。这种突破性的分布式处理方法有效地解决了Kafka诞生时的一系列挑战,如削峰和异步通信。它具有高性能(高吞吐量、低延迟)和数据持久性,满足了大数据时代的数据迁移需求。
多年来,由于蓬勃发展的开源社区和支持该项目的商业公司,一个全面的Kafka生态系统已经形成。许多大大小小的企业都支持Kafka,这充分说明了它作为一种产品的成熟性。
尽管Kafka的简单架构使其得以快速发展并取得领先,但它也为适应不同场景留下了潜在的困难。其中一些挑战包括:
Rebalancing之痛
难以扩展brokers,topics,partitions,replicas
Broker故障处理
延迟和抖动
企业级功能
云迁移
Kafka出现在2010年前后,当时正值大数据的最初爆发期。随着数据量在随后几年的持续增长,功能需求和易用性变得越来越重要。更重要的是,“云原生”的概念开始受到关注,这预示着Kafka将迎来新的挑战者,Apache Pulsar就是其中的佼佼者。
Pulsar:为云原生而生
Kafka的经典架构启发了许多继任者,包括Apache Pulsar。作为云原生环境的下一代消息平台,Pulsar拥有一个计算和存储解耦的架构。
Pulsar Broker充当计算层,而存储由另一个Apache顶级项目Apache BookKeeper支持,这是一个分布式预写日志(WAL)系统。BookKeeper可以有效地处理大量的数据存储任务,元数据来源于ZooKeeper。
Pulsar的分层架构、云原生兼容性以及多租户等开源企业功能在生产中为用户提供了更多的可能性。尽管如此,其复杂的结构也意味着更高的学习成本和就业市场上人才的缺乏。这也是为什么像腾讯这样的大型科技公司支持Pulsar,但较小的公司一直艰难采用它的原因。
与Kafka相比,Pulsar还有很长的路要走,尤其是在其生态系统方面,但自成立以来,它一直保持着强劲的势头。
2012: 雅虎内部开发
2016: Apache 2.0许可下开源
2018: 成为Apache顶级项目
2023: 600+ 贡献者, 12.5K+ stars, 3.3K+ forks
2021年,Pulsar的月活跃贡献者数量超过了Kafka。在成为Apache顶级项目的五年时间里(2013年Kafka和2018年Pulsar),Pulsar如何解决Kafka的痛点?它们之间的一些主要区别是什么?有了以上背景信息,让我们更详细地回顾一下这些问题。
Brokers和Partitions:是否解耦
第一个主要区别是两个系统如何处理代理和分区之间的关系。Kafka的分区和代理是紧密耦合的。当生产者将数据发布到Kafka集群时,它会被写入一个分区。每个分区都有一个具有几个(或零个)follower的leader节点,这些follower在leader失败的情况下复制数据。
这种做法中最困难的部分是分区的数据迁移。如果Kafka分区中有大量数据,那么迁移过程可能是一场噩梦。分区和代理之间的强耦合关系在某种程度上导致了Kafka中的一系列其他问题。
相比之下,在Pulsar中,分区和代理是松散耦合的。分区可以进一步划分为多个segment,这允许跨多个存储节点(即Bookie)对条目进行条带化。换句话说,单个分区中的数据可以存储在具有多个副本的多个节点中。
例如,在分区1中有许多剥离的数据段,并且Segment 1可能在Bookie 1、Bookie 2和Bookie 4中具有副本。如果其中一个Bookie失败,对分区的影响很小,因为它可能只影响一个或几个segment。此外,与整个分区的数据丢失相比,恢复过程要快得多。
当Kafka在十多年前发展起来时,它需要快速增长,并且没有优先考虑细粒度的数据存储和管理。相比之下,Pulsar在这方面提供了一种更复杂的方式,这为其未来的增长带来了更多的空间。
可扩展性
可扩展性是区分这两个消息系统的另一个关键因素。
在Kafka中,有多个代理来接收数据(一个leader具有多个ISR)。在节点发生故障的情况下,该代理上的分区将丢失。它需要手动维护(或脚本)来进行恢复,而且逻辑相对复杂。不能简单地用新的broker替换它,并且不能自动转移以前的broker ID。
另一个痛苦是,由于新代理没有分区,新代理无法立即处理旧代理的流量。需要手动将旧分区迁移到代理。但是,如果数据量很大,迁移可能会很麻烦,如前一节所述。
那么,Pulsar是如何处理同样的问题的呢?
如果Pulsar代理故障,它将失去之前持有的分区的所有权,该分区的信息存储在ZooKeeper中。在检测到变化后,其他代理重新选择一个新的。对于整个Pulsar集群来说,代理故障不是一个重大问题,因为另一个代理可以很快接管。
这个过程的效率在于Pulsar代理是无状态的。当一个代理宕机时,可以立即扩展该代理集群。代理不存储数据,仅作为计算层。Bookie存储数据,他们甚至不需要知道代理发生了什么。
Pulsar中丢失热分区的影响比Kafka中小得多,恢复也快得多。如果需要提高集群处理消息的能力,只需添加代理即可,而无需担心存储层。
Traffic Hotspots
代理处理流量热点的能力和方法在Kafka和Pulsar中有所不同。
在Kafka中,当一个代理有很重的写入负载时,增加代理的数量并没有帮助,因为一次只有一个代理可以处理写入。如果代理有大量读取,添加新的代理也不会起作用,因为其中没有分区。如前所述,Rebalancing流量是另一个棘手的问题。
通常,在Kafka中有两种处理流量热点的解决方案:
增加分区数量带来了重新平衡的巨大困难。
扩大代理的规模以提高其性能。如果代理故障,需要使用另一个代理来处理繁重的流量,这也需要扩容(最终是整个集群),这使得它成为一种成本效率低下的方法。
在Pulsar中,写入热点会导致大量条带化的segment。随着写入更多的数据,代理会生成更多的segment,并在多个Bookie之间进行分配。如有必要,Bookie集群可以简单地扩展以存储新添加的分段(在BookKeeper中也称为ledger)。
对于读取热点,Pulsar依赖于bundle,每个bundle都包含多个topic来满足客户端请求。每个bundle都被分配给一个特定的代理。bundle提供了一种负载均衡机制,允许将超过阈值(例如topic计数和带宽)的bundle拆分为两个新的bundle,其中一个bundle被卸载到新的代理。
写入和读取实现
Kafka和Pulsar如何处理写入和读取请求直接关系到它们的延迟和抖动,这是选择消息系统时的两个重要因素。
Kafka中的写入在很大程度上依赖于操作系统的页面缓存。数据直接写入页面缓存(内存),然后异步写入磁盘。Kafka利用了零拷贝原理,允许数据直接从内存进入磁盘文件。换句话说,Kafka代理不需要为存储数据分配额外的单独场所。
然而,Kafka对页面缓存的严重依赖可能会导致问题。在追赶读取场景中,从文件中读取历史数据需要将数据加载回内存。这可能从缓存中收回未读取的尾部数据(最新数据),导致内存和磁盘之间的交换效率低下。这可能会影响系统的稳定性、延迟和吞吐量。
Pulsar以不同的方式处理数据读取和写入。Pulsar代理充当BookKeeper客户端,并将数据写入ledger。该过程包括将数据作为预写日志写入日志文件(内存),然后异步和顺序地将数据写入日志磁盘。这提供了事务管理并确保了数据的持久性,允许在出现问题时快速回滚。
Pulsar不使用零拷贝,而是依赖JVM堆外内存。当记录事务日志时,数据会进入写缓存,然后存储在两个地方:条目日志缓存,数据异步写入ledger磁盘;ledger缓存,数据异步写入索引磁盘(存储在RocksDB中)。
对于Pulsar中的读取,如果消费者需要读取数据,而数据恰好在内存中(在写缓存中命中,这通常是追尾读取的情况),则可以直接访问数据。如果数据不在写缓存中,它将从读缓存中读取。否则,将根据RocksDB中存储的索引从磁盘中读取数据。一旦检索到数据,就会将其写回读缓存。这样可以确保下次请求数据时,很有可能在读取缓存中找到该数据。
诚然,读取过程涉及许多组件,这可能会导致额外的网络开销和优化困难,有时找出有问题的组件可能很有挑战性。尽管如此,它带来的好处是显而易见的。这种多层架构允许在不同级别进行稳定的数据检索,并且其JVM堆外内存管理是高度可控的(与Kafka相比,Pulsar对内存的依赖更少)。
Kafka和Pulsar中处理读写的不同方法导致了延迟和吞吐量的不同能力。
在大多数情况下,Kafka写入页面缓存时的延迟很低,并且内存足够大,可以处理数据。然而,如果数据消费率很低,并且内存中仍有大量数据,则需要将数据以大块的形式交换到磁盘。如果磁盘速度与内存不匹配(大多数情况下都是这样),则会出现明显的延迟峰值,因为在将内存数据交换到磁盘之前,无法写入传入数据。这会导致抖动,这在延迟敏感的场景中可能是危险的。尽管Pulsar的延迟可能不会低于Kafka,但它的稳定性明显更好。即使有额外的组件和一些性能损失,Pulsar的整体稳定性也是值得权衡的。
吞吐量是Pulsar的优势。它的精简存储实现了最大的吞吐量性能。从理论上讲,Bookie的数量决定了将数据写入磁盘的速度,而这反过来又决定了Pulsar的吞吐量。相比之下,Kafka的吞吐量受到单个代理节点写入速度的限制,因此Pulsar的吞吐量通常优于Kafka。
企业级功能
既然我们已经讨论了Kafka和Pulsar在解决流和消息处理中的一些常见问题时所采取的不同方法,那么让我们从更高的层次回顾一下它们的企业级能力。
Kafka
多租户:单租户系统
数据迁移:依赖Mirror Maker,需要额外维护。市场上也有Confluent Replicator等供应商工具。
分层存储:由供应商提供商业使用。
组件依赖:Kafka Raft(KRaft)从Kafka 2.8开始处于早期访问模式,允许Kafka在没有ZooKeeper的情况下工作。这对Kafka来说是一个显著的优势,因为它简化了Kafka的体系结构并降低了学习成本。
云原生部署:相对复杂
生态系统:一个蓬勃发展的生态系统,拥有各种工具,如connector。
参与者:大量专业人士关注Kafka及其生态系统,使其成为选择Kafka的关键因素。
Pulsar
多租户:内置多租户
数据迁移:内置地理复制,开源、稳定且易于维护。
分层存储:内置分层存储,支持将冷数据移动到更便宜的存储选项,如AWS S3或谷歌云存储。
组件依赖:对Pulsar的一个常见批评是它对ZooKeeper的强烈依赖,以及需要维护额外的存储系统,这需要运维人员掌握更多的技能。
云原生部署:诞生于云原生环境,因为Pulsar将计算与存储分离。企业可以使用Helm或StreamNative Pulsar运维人员在Kubernetes上安装Pulsar。
生态系统:一个不断增长的生态系统,但与Kafka相比要小得多。StreamNative一直致力于创建一个StreamNative Hub来存储Pulsar的生态系统工具。
参与者:Pulsar专业人员和专家较少。
以上仅列出了企业可能感兴趣的一些关键差异。Pulsar还具有其他独特的企业功能,如灵活的订阅模式(独占、故障切换、共享和密钥共享)和选择性确认。
结论
我们通常不会仅仅根据一两个因素来选择技术。即使产品没有关键的缺陷或弱点,我们仍然需要进行更全面的评估。Kafka和Pulsar从一开始就走上了不同的道路。Kafka在大数据领域拥有更多的先发优势,在参与者和生态系统方面无与伦比。然而,它的架构相对陈旧,在云原生时代,面对前景光明的新人Pulsar,它的竞争力已经下降。我们希望本文能够帮助您更好地了解这两个系统,并在中间件选择过程中做出更明智的决策。
版权归原作者 移动云开发者社区 所有, 如有侵权,请联系我们删除。