Apache Pulsar 与 Kafka 性能比较:延迟性(测试方法)
Apache Kafka 的高性能一直广受喜爱,它能在高速处理消息的同时维持低延迟。Apache Pulsar 在同类产品中发展迅速,竞争力突出。
总有文章说 Pulsar 比 Kafka 性能更好,但是想找到测试的原始数据并不容易。另外,很多报告的测试数据并非来自最新版本的 Pulsar 和 Kafka,这两个项目都发展得太快了,因此测试结果对新版本不具有代表性,所以我们决定使用 Kafka(2.3.0)和 Pulsar(2.4.0),进行一系列性能测试,并将测试结果陆续发布出来。
本系列文章将重点讨论延迟性,后续文章中会讨论吞吐量等。
消息系统性能测试
Kafka 和 Pulsar 软件包都包含性能测试工具。我们可以修改任何一个性能测试工具,让它们彼此兼容。我们将使用 OpenMessaging Project 的第三方基准框架。
可参考:http://openmessaging.cloud/
OpenMessaging Project 是一个 Linux Foundation Collaborative Project。OpenMessaging Project 的目标是为消息和流技术提供厂商中立且适用于所有编程语言的标准。这一项目采用了支持多种消息技术的性能测试框架。
测试使用的代码都在 OpenMessaging GitHub 仓库中。
可参考:https://github.com/openmessaging/openmessaging-benchmark
测试最初被设计为在公有云产品上运行,但我们将在 Amazon Web Services(AWS)中使用标准 EC2 实例进行测试。
我们将在 GitHub 上发布每个测试的完整输出结果。欢迎你分析数据并提出见解,当然,你也可以自己测试,获取新数据。我们发现,使用不同系列的 EC2 实例集进行测试,结果相近,因此你的测试结果也不会与我们相差很多。
虽然使用 OpenMessaging 基准工具来运行的测试已经包含了大量工作负载,但是为了让对比测试更有趣,我们决定再加一些负载,这一想法来自 LinkedIn Engineering 网站上一篇名为「Benchmarking Apache Kafka: 2 Million Writes Per Second (On Three Cheap Machines)」的文章。
可参考:https://engineering.linkedin.com/kafka/benchmarking-apache-kafka-2-million-writes-second-three-cheap-machines
这是一篇很久以前的博客了,现在,硬件普遍更好,但是我们并未使用顶配的测试设备。提前剧透:Kafka 和 Pulsar 都可以毫不费力地处理每秒 200 万次的写入,会在后续文章中详述。
OPENMESSAGING 基准测试
OpenMessaging 基准测试是一个开源的可扩展框架。只需添加 Terraform 配置、Ansible playbook 或能在测试工具中控制 producer 和 consumer 的 Java 库,就可以把消息技术添加到测试中。目前,Kafka 和 Pulsar 中的 Terraform 配置是相同的,在 AWS 中启动相同的 EC2 实例集。
为了便于比较,硬件配置应该相同,因此,现有的基准代码简化了 Kafka 和 Pulsar 之间的比较。
在实际测试开始前,我对所有测试进行了预测试。以恒定速率进行了延迟测试,定期记录延迟和吞吐量。
如果你想自己测试的话,需要注意以下几点:在 AWS 上运行测试费用很高;需要大量配置较好的 EC2 实例(对软件基准测试非常重要);如需保证硬件不成为瓶颈,则需配置较好的硬件,而它的成本比较高(每小时不低于 5 美元,一个月要 3800 美元);在不进行测试时(例如,夜里),可以停止运行环境;确保在测试后删除所有资源。
性能注意事项
为了更好地理解测试结果,先介绍几个重要概念。首先,需要检查测试的目的:延迟;然后,检查消息的持久性,尤其是在将消息存储到磁盘时;最后,需要了解 Kafka 和 Pulsar 中不同的消息复制模型。
Kafka 和 Pulsar 之间有许多相似之处,但也有一些影响性能的显著差异。为了公平地评估这两个系统,需要了解以下差异:
关于延迟测试
所有延迟都必须包含应用程序和消息系统之间的网络延迟。假设所有测试的网络配置相同,并且网络产生的延迟也相同,那么网络延迟对所有测试的影响是相同的。在比较延迟时,相同的网络延迟很重要。
我们指出这一点是因为测试结果与 LinkedIn Engineering 博客中的结果不相同。假设博客文章当时的测试在专用的 1 GB 以太网上运行,而我们的测试运行在公有云的实例上,网络带宽为 10 GB。所以,我们的测试结果与那篇文章中的结果直接相比确有不妥。由于在测试中,网络配置是恒量,我们可以比较本次测试中 Kafka 和 Pulsar 消息系统之间的延迟结果。
我们记录了两种类型的延迟:端到端延迟和发布延迟。
端到端延迟
端到端延迟相对简单,指从 producer 发送消息到 consumer 接收消息的时间。在实现 Pulsar 和 Kafka 的基准测试中,发送的时间戳是由各自发送消息的 API 自动生成的。当 consumer 接收到消息时,生成第二个时间戳。这两个时间的差就是端到端延迟。
端到端延迟的复杂之处在于用于测量时间戳的时钟。在测量端到端延迟时,必须同步时间戳的时钟。如果没有同步,时钟之间的差异将会影响测量。最终测量结果实际上是时钟之间的差异,也就是消息系统的延迟。由于时钟会随时间漂移,所以在运行时间长的测试中问题会更严重。
理想情况下,producer 和 consumer 在同一服务器上,使用同一时钟获得时间戳,因此不存在延迟。但是,基准测试的目的是将 producer 和 consumer 分离到不同的服务器上,以分配负载。
另一个最佳方案是尽可能准确地同步服务器之间的时钟。AWS 提供免费的时间同步服务(time sync service),该服务与 chrony 相结合,使 EC2 实例之间的时钟看起来十分接近同步(误差在几微秒内)。在测试中,我们特地在所有客户端服务器上安装了 chrony,并配置使用 AWS 时间源。
发布延迟
发布延迟指消息从 producer 发出到 broker 的这段时间。消息被 broker ack 后,则表明消息被正确地发送到了 broker 且已被持久化。Procuder、broker、consumer 三者相互独立,当 producer 完成发送消息操作之后(收到 ack 指令之后),这条消息的成功与否已经和 producer 没有关系了。一致的低发布延迟对 producer 来说是有益的,在 producer 准备发送消息时,broker 快速接收消息,允许 producer 继续处理 producer 级别的问题,例如,业务逻辑。这种消息的发送是 broker 的关键特性。
在基准测试中,消息采用异步发送的形式,即 producer 不会阻塞消息 ack 的操作。发送消息的调用立即返回,回调在消息到达时进行确认。在异步发送中,发布延迟看起来似乎没那么重要,但其实不然。
Kafka: max.in.flight.requests.per.connection
Pulsar: maxPendingMessages
以上两者都有缓冲区,用来保存未确认的消息。当缓冲区达到设定的阈值时,producer 开始阻塞(或停止,这由配置决定)。因此,如果消息系统没有快速确认收到消息,生产应用程序就会等待消息系统的操作。
在基准测试中,发布延迟指从调用发送方法到触发确认回调的这段时间。这两个时间戳都是在 producer 中生成的,因此无需考虑时钟同步。
持久性与刷新消息到磁盘
消息系统的持久性指在系统出现故障时,消息不会丢失。为了确保这一点,需要将消息存储在安全的位置,即便运行消息系统软件的服务器出现故障,消息也不会丢失。Kafka 和 Pulsar 最终都向磁盘写入消息,以提供持久性。
但是,只要求操作系统向文件系统写入消息是不够的。向文件系统写入意味着将数据存放在写入缓存,但不一定安全地存储在磁盘上。由于缓存驻留在内存中,因此如果服务器崩溃(例如,断电、内核宕机),已经写入缓存但还没有写入或刷新到磁盘的数据将会丢失。强制将缓存数据写入磁盘的操作称为 fsync。为确保消息已经存储在磁盘上,需要触发 fsync 操作,在写入消息后将文件缓存刷新到磁盘。
默认情况下,Kafka 不会显式地将每条消息刷新到磁盘,它会在刷新操作系统时实现磁盘刷新。当服务器崩溃时,未刷新到磁盘的数据可能会丢失。这一默认设置是出于性能考虑的。写入磁盘比写入内存缓存慢,因此磁盘刷新使消息处理性能下降。可以将 Kafka 配置为定期刷新(甚至可以设置为每条消息写入后刷新),但是出于性能考虑,不建议这样做。
默认情况下,Pulsar 将每条消息刷新到磁盘。消息存入磁盘后才向 producer 确认,这在服务器崩溃时提供了更强的持久性保证。Pulsar 在保证持久性的同时,还能保持高性能,是因为它使用 Apache BookKeeper 来存储消息,而 BookKeeper 是专门为此优化的分布式日志存储系统。另外,在 Pulsar 中可以禁止 fsync 操作。
由于刷新磁盘会影响性能,我们将对 Kafka 和 Pulsar 都进行两次测试,一次启用对每条消息进行磁盘刷新,一次禁用。这有助于更好地比较 Kafka 和 Pulsar。
消息复制
Kafka 和 Pulsar 都通过多副本机制来确保消息的高可用。即使丢失了一个消息副本,仍然可以通过其他副本恢复消息。在 Kafka 和 Pulsar 中,消息复制影响性能的方式不同。如何确认测试中 Kafka 和 Pulsar 之间的复制行为相似?
Kafka 使用 leader-follower 复制模型。Kafka 的一个 broker 被选为分区的 leader。首先将所有消息写入 leader,follower 从 leader 中读取并复制消息。Kafka 监控每个 follower 是否与 leader “同步”。使用 Kafka,可以在消息成功保存并被 producer 确认之前控制单个消息的总副本数(复制因子)与需要同步的最小副本数(min.insync.replicas
)。
典型的配置情况是,Kafka 保存消息的 3 份副本,并且只会在至少 2 个副本(大多数)成功写入后立刻确认。这也是我们在所有 Kafka 测试中采用的配置(replication-factor
=3,in.sync.replicas
=2,acks
=all)。
Pulsar 采用 quorum-vote
复制模型。并行写入多个消息副本。一旦确认已存储部分消息副本,便会确认该消息(ack quorum
)。Leader-follower 模型通常向特定主题分区内的同一组 leader 和 follower 写入副本,而 Pulsar 可以将消息副本均匀分摊到不同的存储节点上,从而提高读写性能。
在测试中,为了确保测试的一致性,Pulsar 也采用三副本的机制。Pulsar(配置:ensemble
=3,write
quorum
=3,ack quorum
=2)与 Kafka 的复制结果相似:3 个消息副本,在得到其中任意两个副本的确认之后,立即向 broker 返回消息持久化成功。
点击 链接,可以查看英文原稿。
评论