前言

Kafka 有多快呢?我们可以使用 OpenMessaging Benchmark Framework 测试框架方便地对 RocketMQ、Pulsar、Kafka、RabbitMQ 等消息系统进行对比测试,因为暂时没有测试条件(后续补上),我直接用这篇文章的测试结果(Benchmarking Kafka vs. Pulsar vs. RabbitMQ: Which is Fastest?),可以看到,在某种条件下,Kafka 写入速度比 RabbitMQ 快 15 倍,比 Pulsar 快 2 倍,在最高吞吐量下仍保持低延迟。

那么,为什么 Kafka 可以那么快呢?这里我先简单总结,后面会展开分析。

  1. 从磁盘中顺序读写 event
  2. 通过批处理减少大量小 I/O
  3. 从文件到 socket 之间数据零拷贝
  4. 基于分区的横向扩展

ps:[本系列](博客后台 - 博客园 (cnblogs.com))博客将持续更新。

顺序读写磁盘

Kafka 严重依赖文件系统来读写 event。我们不禁会问,磁盘不是很慢吗?Kafka 真的能提供很好的性能吗?

事实上,磁盘比人们预期的要慢得多,也快得多,这取决于它们的使用方式。在这篇文章中(ACM Queue article)可以发现,在某些情况下,顺序磁盘访问可能比随机内存访问更快。这要得益于现代操作系统对磁盘读写进行的大量的优化,包括 read-ahead 和 write-behind 技术,当我们顺序读取磁盘时,更多时候访问的不是磁盘,而是内存--pagecache。

因此,只要顺序访问文件系统,磁盘也可以很快。Kafka 的 event 组织方式以及应用场景,天然地支持了顺序读写,并且 Kafka 也为此做了许多努力,例如批处理、追加写入等。

此外,相比主动将 event 维护在内存,采用文件系统还有以下好处:

  1. 可以缓存更多的数据。在 JVM 中,维护对象的内存开销将是实际数据大小的两倍甚至更糟,随着堆内数据的增加,gc 将愈发频繁。而使用文件系统可以在 pagecache 中缓存更多更紧凑的数据,而不需要考虑 gc 问题。

  2. 重启后恢复更快。由于数据缓存在 pagecache,进程重启,这部分缓存仍然可以保持 warn 的状态,如果在进程内存中维护这些数据的话,每次启动都需要重建(对于 10GB 缓存可能需要 10 分钟)。

  3. 数据不会丢失。如果数据维护在内存中,需要考虑定期将数据持久化到磁盘,一致性和性能的权衡将是一个比较麻烦的问题,即便如此,我们也不能保证数据不会丢失,例如 redis 可能损失几秒的数据,甚至更多。在理论上,Kafka 就不会出现数据丢失的情况。

  4. 大大简化了代码。用于维护缓存和文件系统之间一致性的所有逻辑现在都在操作系统中,而操作系统往往更高效、更正确。

通过批处理减少小I/O

小 I/O 操作发生在客户端和服务端之间的数据传输以及服务端自身的持久化操作。

为了避免小 I/O 操作,Kafka 是以批的形式来操作 event,而不是一次发送一条消息。producer 会尝试在内存中积累数据,并在单个请求中发送更大的批,当然,这种方式是牺牲少量额外延迟以获得更好的吞吐量,我们可以配置累积数量和等待时间来平衡。同理,consumer 读取数据时也会尝试一次读取更多。

批处理可以产生较大顺序磁盘操作和连续内存块,不过也产生了较大的网络数据包,相应地,Kafaka 会将消息压缩后发送,当消息写入日志时仍然是压缩形式,仅由使用者解压缩。

数据零拷贝

另一个问题是过多的字节复制。//zzs001

一般情况下,数据从文件传输到 socket 的数据路径为:磁盘 -》内核的 pagecache -》用户空间缓冲区 -》内核的 socket 缓冲区 -》NIC 缓冲区。

显然,这是非常低效的,有四个副本和两个系统调用。Kafka 使用 sendfile,允许操作系统将数据从 pagecache 直接发送到网络,即磁盘 -》内核的 pagecache-》NIC 缓冲区。从而避免这种重复复制和系统调用。更多关于 sendfile 的内容可以参考Efficient data transfer through zero copy

需要注意的是,由于 TLS/SSL 库是工作在用户空间的,所以,当启用了 SSL,sendfile 将不能使用。

基于分区的横向扩展

关于这一点,在上一篇博客中其实已经提到过。首先,一个 topic 会划分成一个或多个 partition,这些 partition 一般分布在不同的 broker 实例。producer 发布的 event 会根据某种策略分配到不同的 partition,这样做的好处是,consumer 可以同时从多台 broker 读取 event,从而大大提高吞吐量。另外,为了高可用,同一个 partition 还会有多个副本,它们分布在不同的 broker 实例,和很多传统的消息系统不同,Kafka 的副本是可读的,即 consumer 不仅可以从主 partition 读取 event,也可以从副本读取。//zzs001

结语

以上内容是最近学习 Kafka 的一些思考和总结(主要参考官方文档),如有错误,欢迎指正。

任何的事物,都可以被更简单、更连贯、更系统地了解。希望我的文章能够帮到你。

最后,感谢阅读。

参考资料

Apache Kafka 官方文档

Benchmarking Kafka vs. Pulsar vs. RabbitMQ: Which is Fastest?

The OpenMessaging Benchmark Framework

The Pathologies of Big Data - ACM Queue

Efficient data transfer through zero copy - IBM Developer

相关源码请移步:https://github.com/ZhangZiSheng001/kafka-demo

本文为原创文章,转载请附上原文出处链接:https://www.cnblogs.com/ZhangZiSheng001/p/16788561.html

kafka详解(二)--kafka为什么快的更多相关文章

  1. Kafka详解二:如何配置Kafka集群

    问题导读1.Kafka有哪几种配制方法?2.如何启动一个Consumer实例来消费消息? Kafka集群配置比较简单,为了更好的让大家理解,在这里要分别介绍下面三种配置 单节点:一个broker的集群 ...

  2. kafka详解(一)--kafka是什么及怎么用

    kafka是什么 在回答这个问题之前,我们需要先了解另一个东西--event streaming. 什么是event streaming 我觉得,event streaming 是一个动态的概念,它描 ...

  3. .NET DLL 保护措施详解(二)关于性能的测试

    先说结果: 加了缓存的结果与C#原生代码差异不大了 我对三种方式进行了测试: 第一种,每次调用均动态编译 第二种,缓存编译好的对象 第三种,直接调用原生C#代码 .net dll保护系列 ------ ...

  4. PopUpWindow使用详解(二)——进阶及答疑

      相关文章:1.<PopUpWindow使用详解(一)——基本使用>2.<PopUpWindow使用详解(二)——进阶及答疑> 上篇为大家基本讲述了有关PopupWindow ...

  5. Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)

    [Android布局学习系列]   1.Android 布局学习之——Layout(布局)详解一   2.Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)   3.And ...

  6. logback -- 配置详解 -- 二 -- <appender>

    附: logback.xml实例 logback -- 配置详解 -- 一 -- <configuration>及子节点 logback -- 配置详解 -- 二 -- <appen ...

  7. 爬虫入门之urllib库详解(二)

    爬虫入门之urllib库详解(二) 1 urllib模块 urllib模块是一个运用于URL的包 urllib.request用于访问和读取URLS urllib.error包括了所有urllib.r ...

  8. [转]文件IO详解(二)---文件描述符(fd)和inode号的关系

    原文:https://www.cnblogs.com/frank-yxs/p/5925563.html 文件IO详解(二)---文件描述符(fd)和inode号的关系 ---------------- ...

  9. Android View 的绘制流程之 Layout 和 Draw 过程详解 (二)

    View 的绘制系列文章: Android View 的绘制流程之 Measure 过程详解 (一) Android View 绘制流程之 DecorView 与 ViewRootImpl 在上一篇  ...

随机推荐

  1. 2539-SpringSecurity系列--在有安全验证的情况下做单元测试Test

    在有安全验证的情况下做单元测试Test 版本信息 <parent> <groupId>org.springframework.boot</groupId> < ...

  2. 珠联壁合地设天造|M1 Mac os(Apple Silicon)基于vscode(arm64)配置搭建Java开发环境(集成web框架Springboot)

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_194 也许有人从未听说过Python,但是不会有人没听说过Java,它作为一个拥有悠久历史的老牌编程语言,常年雄踞TIOBE编程语 ...

  3. 编译器工程师眼中的好代码:Loop Interchange

    摘要:本文将以Loop Interchange的场景为例,讲述在编写代码时可以拿到更优性能的书写方式. 本文分享自华为云社区<编译器工程师眼中的好代码(1):Loop Interchange&g ...

  4. Python小游戏——外星人入侵(保姆级教程)第一章 05重构模块game_functions

    系列文章目录 第一章:武装飞船 05:重构:模块game_functions 一.重构 在大型项目中,经常需要在添加新代码前重构既有代码.重构旨在简化既有代码的结构,使其更容易扩展.在本节中,我们将创 ...

  5. mybatisplus-sql注入器

    sql注入器 使用mybatisplus只需要继承BaseMapper接口即可使用:但是有新的需求需要扩展BaseMapper里面的功能时可使用sql注入器. 扩展BaseMapper里面的功能 点击 ...

  6. [HDU6057] Kanade‘s convolution (FWT)

    题面 出自HDU6057 给你两个数列 A [ 0... 2 m − 1 ] A[0...2^m-1] A[0...2m−1] 和 B [ 0... 2 m − 1 ] B[0...2^m-1] B[ ...

  7. Tomcat 10无法使用javax包

    可以导入新的 jakarta包 <dependencies><!--servlet依赖--> <dependency> <groupId>jakarta ...

  8. 尝试理解Linux容器进程与宿主机共享内核到底是什么意思?

    背景 近期接触容器技术时,经常看到各类比较容器与虚拟机区别的文章中会提到:容器是共享宿主机的内核,而虚拟机则是拥有自己独立的内核,所以不可能在Linux上用容器运行windows,但是用虚拟机则可以. ...

  9. RT-Thread Studio增加软件包操作

    RT-Thread Studio增加软件包操作 1. 在本地中完成如下操作 打开RTthread Studio的安装目录 在当前目录下找到env的目录 在env的目录下找到要添加软件包的分类文件夹 本 ...

  10. KingbaseES 中实现mysql的from_days和to_days

    mysql中两个函数的说明: TO_DAYS(date)给出一个日期date,返回一个天数. FROM_DAYS(N)给出一个天数N,返回一个DATE值. 两个函数比较计算的日期都是 0000-01- ...