Apache Kafka,Apache Pulsar和RabbitMQ的基准测试:哪一个是最快的MQ?

2020-10-29 10:44:46 浏览数 (1)

ApacheKafka是最流行的事件流处理系统。在这个领域中有很多同类的系统可以拿来比较。但是最关键的一点就是性能。Kafka以速度著称,但是,它现在能有多快,以及与其他系统相比又如何呢?我们决定在最新的云硬件上测试kafka的性能。 为了进行比较,我们选择了传统的消息broker RabbitMQ和基于Apache Bookeeper的消息broker Apache Pulsar。我们要关注以下几点,1.系统吞吐量。2.系统延迟。因为他们是生产中事件流系统的主要性能指标,特别是吞吐量测试测量每个系统在利用硬件(特别是磁盘和CPU)方面的效率。延迟测试测量每个系统交付实时消息的延迟程度,包括高达p99.9%的尾部延迟,这是实时和任务关键型应用程序以及微服务体系结构的关键需求。 我们发现Kafka提供了最好的吞吐量,同时提供了最低的端到端延迟,最高达到p99.9的百分比。在较低的吞吐量下,RabbitMQ以非常低的延迟交付消息。

Kafka

Pulsar

RabbitMQ mirrored

Peak Throughput(MB/s)

605MB/s

305MB/s

38MB/s

p99 Latency(ms)

5 ms(200 MB/s load)

25 ms(200 MB/s load)

1 ms*(reduced 30 MB/s load)

当吞吐量高于30MB/s时,RabbitMQ延迟会显著降低。此外,在更高的吞吐量和更好的延迟情况下,镜像的影响是显著的,可以通过只使用经典队列而不使用镜像来实现。

背景

首先,让我们简要地讨论每个系统,以了解它们的高级设计和体系结构,查看每个系统所做的权衡。

Kafka

Kafka是一个开源的分布式事件流媒体平台,也是Apache软件基金会五个最活跃的项目之一。在其核心,Kafka被设计成一个复制的、分布式的、持久的日志提交系统,用于支持事件驱动的微服务或大规模流处理应用程序。客户端直接从代理集群生成或使用事件,这些代理持久地向底层文件系统读/写事件,并在集群中同步或异步地自动复制事件,以实现容错性和高可用性。

Pulsar

是一个开源的分布式发布/订阅消息传递系统,最初是为排队用例服务的。它最近还增加了事件流功能。Pulsar被设计为一层(几乎)无状态代理实例,它连接到单独的BookKeeper实例层,后者实际读取/写入消息,可选地持久存储/复制消息。Pulsar并不是它的唯一系统,还有其他的消息传递系统,比如Apache DistributedLog和Pravega,它们都是在BookKeeper之上创建的,旨在提供一些类似kafka的事件流功能。

BookKeeper

BookKeeper 是一个开源的分布式存储服务,最初设计为Apache™Hadoop®的NameNode预写日志。它提供账簿中消息的持久存储,跨称为赌博的服务器实例。每个下注者同步地将每条消息写入本地日志以进行恢复,然后异步地写入其本地索引分类账存储。与卡夫卡broker不同,bookies之间不进行通信,是 BookKeeper clients使用quorum风格的协议在bookies之间复制消息。

RabbitMQ

RabbitMQ是一个开源的传统消息传递中间件,它实现了AMQP消息传递标准,满足了低延迟排队用例的需求。RabbitMQ由一组代理进程组成,这些进程托管向其发布消息的“交换器”,并对从中消费的消息进行排队。可用性和持久性是提供的各种队列类型的属性。可用性和持久性是提供的各种队列类型的属性。经典队列提供的可用性保证最少。经典镜像队列将消息复制到其他代理并提高可用性。通过最近引入的仲裁队列提供了更强的持久性,但以性能为代价。由于这是一篇面向性能的博客文章,所以我们将评估限制在经典队列和镜像队列。

分布式系统的持久性

单节点存储系统(例如RDBMS)依靠同步写入磁盘来确保最大的持久性。但在分布式系统中,持久性通常来自复制,即数据的多个副本独立失效。数据同步只是在发生故障时减少故障影响的一种方法(例如,更频繁地同步可能导致更短的恢复时间)。相反,如果有足够多的副本失败,那么无论是否使用fsync,分布式系统都可能无法使用。因此,我们是否使用fsync只是一个问题,即每个系统选择什么来保证其复制设计。虽然有些密切依赖于从不丢失写入到磁盘的数据,因此在每次写入时都需要fsync,但其他一些则在其设计中处理这种情况。 Kafka的复制协议经过精心设计,可以确保一致性和持久性,而无需通过跟踪已同步到磁盘和未同步到磁盘的内容来同步fsync。通过更少的假设,Kafka可以处理更大范围的故障,比如文件系统级别的损坏或意外的磁盘解除配置,并且不会想当然地认为没有被fsync的数据是正确的。Kafka还能够利用操作系统对磁盘进行批处理,以获得更好的性能。 我们还不能明确地确定BookKeeper是否在不同步每个写操作的情况下提供了相同的一致性保证——特别是在没有同步磁盘持久性的情况下,它是否可以依赖复制来实现容错。文档或底层复制算法中没有涉及到这一点。基于我们的检查和BookKeeper实现了一个分组fsync算法的事实,我们相信它确实依赖于对每个编写进行同步以确保其正确性,但我们希望听到社区中的人们的意见,她们可能更了解我们结论的真确性。 无论如何,由于这可能是一个有争议的话题,我们给出了这两种情况下的结果,以确保我们尽可能的公平和完整,尽管运行带有同步fsync的Kafka是极其罕见的,也是不必要的。

基准测试框架

修正了OMB Kafka驱动程序

我们修复了Kafka驱动程序中一个严重的bug,这个bug让Kafka生产商无法获得TCP连接,瓶颈只能连接到每个worker实例。与其他系统相比,这个补丁使得Kafka的数字更加公平——也就是说,现在所有的系统都使用相同数量的TCP连接来与各自的代理通信。我们还修复了Kafka基准消费者驱动程序中的一个关键bug,即偏移量提交的过于频繁且同步导致性能下降,而其他系统是异步执行的。我们还调优了Kafka消费者获取大小和复制线程,以消除在高吞吐量下获取消息的瓶颈,并配置与其他系统相当的代理。

修正了OMB RabbitMQ驱动程序

我们增强了RabbitMQ以使用路由键和可配置的交换类型(直接交换和主题交换),还修复了RabbitMQ集群设置部署工作流中的一个bug。路由密钥被引入来模仿每个主题分区的概念,相当于Kafka和Pulsar上的设置。我们为RabbitMQ部署添加了一个TimeSync工作流,以同步客户端实例之间的时间,从而精确地测量端到端延迟。此外,我们修复了RabbitMQ驱动程序中的另一个bug,以确保准确地测量端到端延迟。

修正了OMB的Pulsar驱动

对于OMB Pulsar驱动程序,我们添加了为Pulsar生成器指定最大批处理大小的功能,并关闭了任何全局限制,这些限制可能人为地限制跨分区的生成器队列在更高的目标率下的吞吐量。我们不需要对脉冲星基准驱动程序做任何其他重大改变。

测试平台

OMB包含针对其基准的测试床定义(实例类型和JVM配置)和工作负载驱动程序配置(生产者/消费者配置和服务器端配置),我们将其用作测试的基础。所有测试都部署了四个worker实例来驱动工作负载,三个代理/服务器实例,一个监视实例,以及Kafka和Pulsar可选的三个实例的Apache ZooKeeper集群。在试验了几种实例类型之后,我们确定了Amazon EC2实例的网络/存储优化类,它具有足够的CPU核心和网络带宽来支持磁盘I/O绑定的工作负载。在下面的部分中,我们将列出我们在不同测试过程中对这些基线配置所做的任何更改。

磁盘

具体来说,我们选择了i3en.2xlarge(带有8个vcore, 64 GB RAM, 2x 2500 GB NVMe ssd)的高25 Gbps网络传输限制,确保测试设置不受网络限制。这意味着这些测试度量的是各自的最大服务器性能度量,而不仅仅是网络的速度。i3en.2xlarge实例在两个磁盘上支持高达655 MB/s的写吞吐量,这给服务器带来了很大的压力。有关详细信息,请参阅完整的实例类型定义。根据一般建议和最初的OMB设置,Pulsar使用一个磁盘记录日志,另一个用于账簿存储。卡夫卡和RabbitMQ的磁盘设置没有变化。

使用dd Linux命令进行测试,作为吞吐量测试的指南:

代码语言:javascript复制
Disk 1
dd if=/dev/zero of=/mnt/data-1/test bs=1M count=65536 oflag=direct
65536 0 records in
65536 0 records out
68719476736 bytes (69 GB) copied, 210.278 s, 327 MB/s

Disk 2
dd if=/dev/zero of=/mnt/data-2/test bs=1M count=65536 oflag=direct
65536 0 records in
65536 0 records out
68719476736 bytes (69 GB) copied, 209.594 s, 328 MB/s

操作系统调优

此外,对于所比较的三个系统,我们使用tune -adm的延迟性能配置文件对操作系统进行了调优,以获得更好的延迟性能,该配置文件禁用磁盘和网络调度器的任何动态调优机制,并使用性能调控器进行CPU频率调优。它将每个核心的p-状态固定在可能的最高频率上,并将I/O调度器设置为截止日期,从而提供一个可预测的磁盘请求延迟上限。最后,它还调优内核中的电源管理服务质量(QoS),以提高性能,而不是节省电源。

内存

i3en.2xlarge与默认的OMB实例相比,调优Kafka和RabbitMQ以使其与测试实例兼容非常简单。两者都主要依赖于操作系统的页面缓存,随着新实例的出现,页面缓存会自动缩小。 然而,Pulsar代理和簿记员都依赖于堆外/直接内存进行缓存,为了在i3en.2xlarge上良好运行,我们调整了这两个独立进程的JVM堆/最大直接内存大小。2超大实例。具体来说,我们将堆大小从每个24 GB(在原始的OMB配置中)减半为每个12 GB,在两个进程和操作系统之间按比例划分了可用物理内存。 在我们的测试中,我们遇到了java.lang.OutOfMemoryError:在高目标吞吐量下的直接缓冲区内存错误,如果堆大小再低一点,就会导致赌博公司完全崩溃。这是使用堆外内存的系统所面临的典型内存调优问题。虽然直接字节缓冲区是避免Java GC的一个有吸引力的选择,但是在大范围内驯服它们是一个具有挑战性的练习。

吞吐量测试

我们首先要测量的是,在网络、磁盘、CPU和内存资源相同的情况下,每个系统能够实现的峰值稳定吞吐量。我们将稳定峰值吞吐量定义为消费者可以在不增加积压的情况下保持的最高平均生产者吞吐量。

fsync的影响

如前所述,Apache Kafka的默认建议配置是使用底层操作系统指定的页面缓存刷新策略(而不是同步地同步每个消息)将消息刷新到磁盘,并依赖复制来保持持久性。从根本上说,这提供了一种简单而有效的方法来分摊Kafka的produce所使用的不同批次的成本,从而在所有条件下实现最大可能的吞吐量。如果Kafka在每次写的时候都被配置为fsync,那么我们只能通过强制fsync系统调用人为地阻碍性能,而没有任何额外的好处。 也就是说,考虑到我们将要讨论这两种情况的结果,我们仍然有必要了解同步对每个Kafka编写的影响。各种生产者批量大小对Kafka吞吐量的影响如下所示。吞吐量随着批处理大小的增加而增加,直到到达“最佳点”,即批处理大小足够高,足以完全饱和底层磁盘。将Kafka上的每条消息同步到磁盘(图2中的橙色条)可以产生与较高批处理大小类似的结果。注意,这些结果仅在所描述的试验环境上的ssd上得到的验证。Kafka确实在所有批处理大小上充分利用了底层磁盘,在较低批处理大小上最大化IOPS,在较高批处理大小上最大化磁盘吞吐量,甚至在强制fsync每条消息时也是如此。

也就是说,从上面的图表可以明显看出,使用默认的fsync设置(绿色条)可以让Kafka代理更好地管理页面刷新,从而提供更好的总体吞吐量。特别是,对于较低的生成器批处理大小(1 KB和10 KB),使用默认同步设置的吞吐量比同步每条消息的吞吐量高3 - 5倍。然而,对于较大的批(100 KB和1 MB),同步的成本是平摊的,吞吐量与默认fsync设置相当。 Pulsar在生产者上实现了类似的批量处理,并在bookies之间对产生的消息进行quoro风格的复制。簿记员在应用程序级实现对磁盘的分组提交/同步,以类似地最大化磁盘吞吐量。簿记员,在默认情况下(由journalSyncData=true bookie配置控制),fsyncs写入磁盘。 了覆盖所有的基础,我们用BookKeeper上的journalSyncData=false配置测试了Pulsar,并与Kafka的默认值进行了比较,建议设置不同步每条单独的消息。但是,我们遇到了簿记员的大延迟和不稳定性,表示与刷新相关的排队。我们还用Pulsar搭载的Pulsar -perf工具验证了同样的行为。据我们所知,在咨询了Pulsar社区后,这似乎是一个错误,所以我们选择从我们的测试中排除它。尽管如此,考虑到我们可以看到磁盘在使用journalSyncData=true时吞吐量达到最大,我们相信它无论如何不会影响最终结果。

RabbitMQ操作一个持久队列,当且仅当消息尚未被使用时,该队列将消息持久保存到磁盘。然而,与卡夫卡和Pulsar不同,RabbitMQ不支持“重新消费”队列来再次读取较旧的消息。从持久性的角度来看,我们的基准测试表明,消费者与生产者保持同步,因此我们没有注意到任何写入磁盘的操作。我们还设置了RabbitMQ,通过在三个代理的集群中使用镜像队列来提供与Kafka和Pulsar相同的可用性保证。

测试设置

本实验按照以下原则和预期保证进行设计:

  • 将消息复制到3x以实现容错(请参阅下面的具体配置)。
  • 我们为这三个系统启用批处理,以优化吞吐量。我们批处理最多1mb的数据,最多10毫秒。
  • Pulsar和Kafka在一个Topic上配置了100个分区。
  • RabbitMQ不支持主题中的分区。为了匹配Kafka和Pulsar设置,我们声明了单个直接交换(相当于主题)和链接队列(相当于分区)。关于这个设置的更多细节可以在下面找到。

OMB使用一个自动速率发现算法,该算法通过以几个速率探测积压来动态地获取目标生产者吞吐量。在许多情况下,我们看到了从2.0消息/秒到500,000消息/秒的确定速率的剧烈波动。这严重影响了实验的重复性和逼真度。在我们的实验中,我们在不使用此特性的情况下显式地配置了目标吞吐量,并在10K、50K、100K、200K、500K和每秒100万条生产者消息的范围内稳步提高了目标吞吐量,四个生产者和四个消费者使用1 KB的消息。然后,我们观察了每个系统在不同配置下提供稳定终端性能的最大速率。

吞吐量结果

我们发现Kafka在我们所比较的系统中提供了最高的吞吐量。考虑到它的设计,产生的每个字节只在一个编码路径上写入一次磁盘,这个编码路径已经被世界各地的数千个组织优化了近十年。我们将在下面更详细地研究每个系统的这些结果。

我们将Kafka配置为使用批处理。大小= 1 mb和徘徊。ms=10,以便生产者有效地批处理发送给代理的写操作。此外,我们在生成器中配置了acks=all和min.insync。replicas=2确保每个消息在返回给生成器之前至少复制到两个代理。我们发现Kafka能够有效地最大限度地使用每个代理上的磁盘——这是存储系统的理想结果。有关详细信息,请参阅Kafka的驱动程序配置。

该图显示了Kafka代理上的I/O利用率和相应的生产者/消费者吞吐量(来源:Prometheus节点度量)。查看原始结果了解详细信息。 我们还对Kafka进行了基准测试,采用了另一种配置,即使用flush将所有副本上的每个消息同步到磁盘。消息= 1和冲洗。确认写入之前的ms=0。结果如下图所示,非常接近默认配置。

查看原始结果了解详细信息。 Pulsar的producer与Kafka的工作方式不同,在于它如何通过队列产生请求。具体来说,它在内部有每个分区的生成器队列,以及对这些队列大小的限制,这些限制对来自给定生成器的所有分区的消息数量设置了上限。为了避免Pulsar生成器在发送的消息数量上造成瓶颈,我们将每个分区和全局限制设置为无穷大,同时匹配1mb的基于字节的批处理限制。

代码语言:javascript复制
.batchingMaxBytes(1048576) // 1MB
.batchingMaxMessages(Integer.MAX_VALUE)
.maxPendingMessagesAcrossPartitions(Integer.MAX_VALUE);

我们还为Pulsar提供了更高的基于时间的批处理限制,即batchingMaxPublishDelayMs=50,以确保批处理主要是由字节限制引起的。我们通过不断增加这个值,直到它对脉冲星最终达到的峰值稳定吞吐量没有可测量的影响,从而达到这个值。对于复制配置,我们使用了ensemble blesize =3、writeQuorum=3、ackQuorum=2,这与Kafka的配置方式相同。有关细节,请参阅Pulsar基准驱动配置。 在BookKeeper的设计中,下注者将数据写入本地日志和分类帐中,我们注意到峰值稳定吞吐量实际上是Kafka能够实现的一半。我们发现,这种基本的设计选择对吞吐量有深远的负面影响,直接影响成本。一旦日志磁盘对簿记员的经纪人完全饱和,脉冲星的生产者率被限制在那一点上。

为了进一步验证这一点,我们还配置了BookKeeper在RAID 0配置中使用两个磁盘,这为BookKeeper提供了在两个磁盘上条纹日志和分类帐写操作的机会。我们能够观察到脉冲星最大限度地利用了磁盘的综合吞吐量(~650 MB/s),但仍然限制在~340 MB/s的峰值稳定吞吐量。

Pulsar有一个分层架构,BookKeeper bookies (存储)与Pulsar代理(存储的缓存/代理)分开。为了完整性,我们在分层部署中运行吞吐量测试,将Pulsar代理移动到另外三个计算优化的c5n.2xlarge上(拥有8个vcore, 21 GB RAM,最多25 Gbps网络传输,ebs支持的存储)实例。BookKeeper 节点保留在存储优化的i3ei3en.2xlarge上。这使得在这个特殊的设置中,Pulsar和BookKeeper总共有6个实例/资源,比Kafka和RabbitMQ多了2倍CPU资源和33%的内存。 即使在高吞吐量下,系统也主要受到I/O限制,而且我们没有发现这种设置有任何改进。此特定运行的完整结果见下表。事实上,Pulsar的两层架构似乎只是增加了更多的开销——两个jvm占用更多的内存、两倍的网络传输以及系统架构中更多的移动部件。我们预计,当网络受到限制时(不像我们的测试提供了过剩的网络带宽),Pulsar的两层架构将以两倍的速度耗尽网络资源,从而降低性能。

Pulsar Deployment Model

Peak Produce Throughput (MB/s)

Tiered

305.73

Co-located

305.69

与Kafka和Pulsar不同的是,RabbitMQ在一个主题中没有分区的概念。相反,RabbitMQ使用一个交换器将消息路由到链接队列,使用头属性(头交换)、路由键(直接和主题交换)或绑定(扇面交换),消费者可以从这些交换器处理消息。为了匹配工作负载的设置,我们声明了单个直接交换(相当于主题)和链接队列(相当于分区),每个队列专用于为特定的路由键提供服务。端到端,我们让所有生产者用所有路由键(轮询)生成消息,让消费者专用于每个队列。我们还通过社区建议的最佳实践优化了RabbitMQ:

  • 启用复制(将队列复制到集群中的所有节点)
  • 消息持久性被禁用(队列仅在内存中)
  • 消费者自动包装启用
  • 跨代理的负载平衡队列
  • 24个队列,因为RabbitMQ每个队列使用一个专用的核心(8个vcpu x 3个代理)

RabbitMQ在复制开销方面表现不佳,这严重降低了系统的吞吐量。我们注意到,在此工作负载期间,所有节点都是CPU绑定的(见下图中右y轴的绿线),几乎没有留出任何空间来代理任何其他消息。详细信息请参见RabbitMQ驱动程序配置。

延迟测试

考虑到流处理和事件驱动架构的日益流行,消息传递系统的另一个关键方面是消息从生产者通过系统穿过管道到消费者的端到端延迟。我们设计了一个实验,以每个系统在不显示任何过度使用迹象的情况下能够维持的最高稳定吞吐量对所有三个系统进行比较。 为了优化延迟,我们更改了所有系统的生成器配置,将消息批处理最多仅为1 ms(而我们用于吞吐量测试的是10 ms),并让每个系统保持默认推荐配置,同时确保高可用性。Kafka被配置为使用其默认的fsync设置(例如,fsync off), RabbitMQ被配置为在镜像队列的同时不持久化消息。在反复运行的基础上,我们选择将Kafka和Pulsar在200K消息/s或200MB/s下进行比较,这低于这个测试环境上单个磁盘300mb /s的吞吐量限制。我们观察到,当吞吐量超过30K消息/s时,RabbitMQ将面临CPU瓶颈。

Kafka始终如一地提供比Pulsar更低的延迟。在这三个系统中,RabbitMQ实现了最低的延迟,但考虑到其有限的垂直可伸缩性,其吞吐量要低得多。由于实验的设置是有意的,因此对于每个系统,消费者总是能够跟上生产者的进度,因此几乎所有的读取都是从所有三个系统的缓存/内存中提供的。 Kafka的大部分性能可以归因于为消费者进行了大量优化的读取实现,它建立在高效的数据组织之上,没有任何额外的开销,比如数据跳过。Kafka充分利用了Linux页面缓存和零复制机制来避免将数据复制到用户空间中。通常,许多系统(如数据库)都构建了应用程序级缓存,从而为支持随机读/写工作负载提供了更大的灵活性。但是,对于消息传递系统,依赖页面缓存是一个很好的选择,因为典型的工作负载执行顺序读/写操作。Linux内核经过多年的优化,能够更聪明地检测这些模式,并使用预读等技术来极大地提高读取性能。类似地,构建在页面缓存之上允许Kafka采用基于发送文件的网络传输,以避免额外的数据副本。为了与吞吐量测试保持一致,我们还通过将Kafka配置为fsync每条消息来运行相同的测试。 Pulsar采用了一种与Kafka非常不同的缓存方法,其中一些源于BookKeeper的核心设计选择,即将日志和分类账存储分开。除了Linux页面缓存之外,Pulsar还采用了多层缓存,即簿记器上的预读缓存(在我们的测试中保留了OMB默认值dbStorage_readAheadCacheMaxSizeMb=1024),托管分类帐(managedLedgerCacheSizeMB,在我们的测试中,20%的可用直接内存为12 GB = 2.4 GB)。在我们的测试中,我们没有观察到这种多层缓存的任何好处。事实上,多次缓存可能会增加部署的总体成本,我们怀疑在12 GB的堆外使用中存在相当大的填充,以避免在前面提到的直接字节缓冲区中遇到Java GC问题。 RabbitMQ的性能是生产者端交换和消费者端绑定到这些交换的队列的一个因素。对于延迟实验,我们使用了与吞吐量实验相同的镜像设置,特别是直接交换和镜像队列。由于CPU瓶颈,我们无法驱动高于38K message /s的吞吐量,并且以这个速率度量延迟的任何尝试都显示了性能的显著下降,p99延迟几乎达到了2秒。 逐渐将吞吐量从38K消息/秒降低到30K消息/秒,这允许我们建立一个稳定的吞吐量,此时系统似乎不会被过度利用。p99延迟为1 ms,这一点得到了很好的证实。我们认为,在3个节点上复制24个队列的开销似乎对较高吞吐量下的端到端延迟有严重的负面影响,而吞吐量小于30K消息/s或30mb /s(纯品红线)允许RabbitMQ交付比其他两个系统更低的端到端延迟。 通常,遵循它的最佳实践允许RabbitMQ提供有限的延迟。鉴于实验故意设置的延迟,这样消费者总是能跟上生产者,RabbitMQ的消息管道效率归结为上下文切换的次数Erlang梁VM(因此CPU)需要做处理队列。因此,通过为每个CPU核心分配一个队列来限制这一点可以提供最低的延迟。此外,使用直接或主题交换允许对特定队列进行复杂的路由(类似于Kafka和Pulsar上专用于分区的用户)。但是直接交换提供了更好的性能,因为没有通配符匹配,这会增加更多的开销,并且是这个测试的合适选择。

在本节的开始,我们已经讨论了Kafka的默认、推荐的fsync配置(实绿线)的延迟结果。在Kafka fsync的每条消息到磁盘(绿色点线)的替代配置中,我们发现Kafka仍然比Pulsar具有更低的延迟,几乎一直到p99.9百分位,而Pulsar(蓝色线)在更高的尾部百分位上表现更好。而推理约尾延时准确p99.9th百分以上是困难的,我们相信非线性延迟拍摄的p99.9th百分位替代卡夫卡fsync配置(虚线绿线)可以归因于角落案件卡夫卡生产国,鉴于生产商延迟似乎遵循相同的趋势。

我们承认,每个系统在设计时都有一定的权衡。尽管对Kafka和Pulsar不公平,但我们发现比较RabbitMQ在配置上的高可用性与Kafka和Pulsar很有趣,这两种配置都以较低的延迟为代价,提供了更强的持久性保证,并且可用性是RabbitMQ的三倍。这可能与某些用例相关(例如,设备位置跟踪),在这里,用可用性来换取更好的性能是可以接受的,特别是当用例要求实时消息传递并且对可用性问题不敏感时。我们的结果表明,当禁用复制时,RabbitMQ可以在更高的吞吐量下更好地维持较低的延迟,尽管即使提高的吞吐量(100K消息/s)仍远低于Kafka和Pulsar所能达到的水平。 尽管Kafka和Pulsar速度较慢(p99的时钟分别为5毫秒和25毫秒),但它们提供的持久性、更高的吞吐量和更高的可用性对于处理金融事务或零售库存管理等大规模事件流用例来说是至关重要的。对于需要较低延迟的用例,RabbitMQ只要负载较轻,就可以实现p99 ~1 ms的延迟,因为消息只是在内存中排队,没有复制开销。 在实践中,操作人员需要小心地提供RabbitMQ,以保持足够低的速率来维持这些低延迟,否则延迟将迅速显著地降低。但是这个任务是困难的,甚至实际上不可能在所有用例中以通用的方式实现。总的来说,一个具有更低操作开销和成本的更好的架构选择可能是为所有用例选择一个像Kafka这样的持久系统,其中系统可以在所有负载级别上以低延迟提供最好的吞吐量。

总结

在这篇博客中,我们对Kafka、RabbitMQ和Pulsar这三种消息传递系统进行了全面、均衡的分析,得出了以下结论。

  • 吞吐量 Kafka提供了所有系统中最高的吞吐量,比RabbitMQ快15倍,比Pulsar快2倍。
  • 延迟 Kafka在较高的吞吐量下提供了最低的延迟,同时还提供了强大的持久性和高可用性。Kafka在它的默认配置中比Pulsar在所有延迟基准中都要快,并且它在每条消息设置为fsync时快到p99.9。RabbitMQ可以实现比Kafka更低的端到端延迟,但只能在显著更低的吞吐量。
  • 开销/复杂性:成本往往是性能的逆函数。Kafka作为具有最高稳定吞吐量的系统,由于其高效的设计,提供了所有系统中最好的价值(即,每字节写入成本)。事实上,Twitter的卡夫卡之旅远离了像脉冲星这样的基于书本的架构,这证实了我们的观察:卡夫卡较少的移动部件显著降低了它的成本(在Twitter的例子中高达75%)。此外,将ZooKeeper从Apache Kafka中移除的工作(参见KIP-500)正在进行中,并进一步简化了Kafka的架构。

虽然这个博客完全关注性能,但是在比较分布式系统时还有很多要讨论的。如果您有兴趣了解更多关于Kafka、Rabbit、Pulsar和类似系统的分布式系统设计中细微差别的权衡,请关注即将发布的新博客文章。

关于作者

Alok Nikhil 是Confluent的一名软件工程师,在基于云的Kafka团队工作。在加入Confluent之前,他在Amazon Web Services从事无服务器关系数据库的工作,在Cisco Research从事高性能矢量包处理器的工作。 Vinoth Chandar在Confluent推动各种流处理工作。在加入Confluent之前,Vinoth已经在Uber和LinkedIn等公司建立了大规模的、关键任务的基础设施系统。Vinoth也是Apache Hudi项目的共同创建者,该项目在过去的几年中改变了数据湖架构的面貌。Vinoth对统一数据存储/处理架构非常感兴趣。

0 人点赞