您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

为什么 Kafka 的吞吐量那么高?

时间:2023-11-08 14:27:51  来源:微信公众号  作者:古明地觉的编程教室

在众多的消息中间件中,Kafka 的性能和吞吐量绝对是顶尖级别的,那么问题来了, Kafka 是如何做到高吞吐的。在性能优化方面,它使用了哪些技巧呢?下面我们就来分析一下。

以'批'为单位

批量处理是一种非常有效的提升系统吞吐量的方法,操作系统提供的缓冲区也是如此。在 Kafka 内部,消息处理是以"批"为单位的,生产者、Broker、消费者,都是如此。

在 Kafka 的客户端 SDK 中,生产者只提供了单条发送的 send() 方法,并没有提供任何批量发送的接口。原因是 Kafka 根本就没有提供单条发送的功能,是的你没有看错,虽然它提供的 API 每次只能发送一条消息,但实际上 Kafka 的客户端 SDK 在实现消息发送逻辑的时候,采用了异步批量发送的机制。

当你调用 send() 方法发送一条消息之后,无论你是同步发送还是异步发送,Kafka 都不会立即就把这条消息发送出去。它会先把这条消息,存放在内存中缓存起来,然后选择合适的时机把缓存中的所有消息组成一批,一次性发给 Broker。简单地说,就是攒一波一起发。

而 Kafka Broker 在收到这一批消息后,也不会将其还原成多条消息、再一条一条地处理,这样太慢了。Kafka 会直接将"批消息"作为一个整体,也就是说,在 Broker 整个处理流程中,无论是写入磁盘、从磁盘读出来、还是复制到其他副本,在这些流程中,批消息都不会被解开,而是一直作为一条"批消息"来进行处理的。

在消费时,消息同样是以批为单位进行传递的,消费者会从 Broker 拉到一批消息。然后将批消息解开,再一条一条交给用户代码处理。

比如生产者发送 30 条消息,在业务程序看来虽然是发送了 30 条消息,但对于 Kafka 的 Broker 来说,它其实就是处理了 1 条包含 30 条消息的"批消息"而已。显然处理 1 次请求要比处理 30 次请求快得多,因为构建批消息和解开批消息分别在生产者和消费者所在的客户端完成,不仅减轻了 Broker 的压力,最重要的是减少了 Broker 处理请求的次数,提升了总体的处理能力。

批处理只能算是一种常规的优化手段,它是通过减少网络 IO 从而实现优化。而 Kafka 每天要处理海量日志,那么磁盘 IO 也是它的瓶颈。并且对于处在同一个内网的数据中心来说,相比读写磁盘,网络传输是非常快的。

接下来我们看一下,Kafka 在磁盘 IO 这块儿做了哪些优化。

磁盘顺序读写

我们知道 kafka 是将消息存储在文件系统之上的,高度依赖文件系统来存储和缓存消息,因此可能有人觉得这样做效率是不是很低呢?因为要和磁盘打交道,而且使用的还是机械硬盘

首先机械硬盘不适合随机读写,但如果是顺序读写,那么吞吐量实际上是不差的。在 SSD(固态硬盘)上,顺序读写的性能要比随机读写快几倍,如果是机械硬盘,这个差距会达到几十倍。因为操作系统每次从磁盘读写数据的时候,需要先寻址,也就是先要找到数据在磁盘上的物理位置,然后再进行数据读写。如果是机械硬盘,这个寻址需要比较长的时间,因为它要移动磁头,这是个机械运动,机械硬盘工作的时候会发出咔咔的声音,就是移动磁头发出的声音。

顺序读写相比随机读写省去了大部分的寻址时间,因为它只要寻址一次,就可以连续地读写下去,所以说性能要比随机读写好很多。

而 kafka 正是利用了这个特性,任何发布到分区的消息都会被追加到 "分区数据文件" 的尾部,如果一个文件写满了,就创建一个新的文件继续写。消费的时候,也是从某个全局的位置开始,也就是某一个 log 文件中的某个位置开始,顺序地把消息读出来。这样的顺序写操作让 kafka 的效率非常高。

使用 PageCache

任何系统,不管大小,如果想提升性能,使用缓存永远是一个不错的选择,而 PageCache 就是操作系统在内存中给磁盘上的文件建立的缓存,它是由内核托管的。无论我们使用什么语言,编写的程序在调用系统的 API 读写文件的时候,并不会直接去读写磁盘上的文件,应用程序实际操作的都是 PageCache,也就是文件在内存中缓存的副本。

应用程序在写入文件的时候,操作系统会先把数据写入到内存中的 PageCache,然后再一批一批地写到磁盘上。读取文件的时候,也是从 PageCache 中来读取数据,这时候会出现两种可能情况。

一种是 PageCache 中有数据,那就直接读取,这样就节省了从磁盘上读取的时间;另一种情况是,PageCache 中没有数据,这时候操作系统会引发一个缺页中断,应用程序的读取线程会被阻塞,操作系统把数据从文件复制到 PageCache 中,然后应用程序再从 PageCache 继续把数据读出来,这时会真正读一次磁盘上的文件,这个读的过程就会比较慢。

用户的应用程序在使用完某块 PageCache 后,操作系统并不会立刻就清除这个 PageCache,而是尽可能地利用空闲的物理内存保存这些 PageCache,除非系统内存不够用,操作系统才会清理掉一部分 PageCache。清理的策略一般是 LRU 或它的变种算法,核心逻辑就是:优先保留最近一段时间最常使用的那些 PageCache。

另外 PageCache 还有预读功能,假设我们读取了 1M 的内容,但 linux 实际读取的却并不止 1M,因为这样你后续再读取的时候就不需要从磁盘上加载了。因为从磁盘到内存的数据传输速度是很慢的,如果物理内存有空余,那么就可以多缓存一些内容。

而 Kafka 在读写消息文件的时候,充分利用了 PageCache 的特性。一般来说,消息刚刚写入到服务端就会被消费,读取的时候,对于这种刚刚写入的 PageCache,命中的几率会非常高。也就是说,大部分情况下,消费读消息都会命中 PageCache,带来的好处有两个:一个是读取的速度会非常快,另外一个是,给写入消息让出磁盘的 IO 资源,间接也提升了写入的性能。

ZeroCopy(零拷贝)

Kafka 还使用了零拷贝技术,首先 Broker 将消息发送给消费者的过程如下:

  • 将指定的消息日志从文件读到内存中;
  • 将消息通过网络发送给消费者客户端;

这个过程会经历几次复制,以及用户空间和内核空间的切换,示意图如下。

为什么 Kafka 的吞吐量那么高?

整个过程大概是以上 6 个步骤,我们分别解释一下。

1)应用程序要读取磁盘文件,但只有内核才能操作硬件设备,所以此时会从用户空间切换到内核空间。

2)通过 DMA 将文件读到 PageCache 中,此时的数据拷贝是由 DMA 来做的,不耗费 CPU。关于 DMA,它是一种允许硬件系统访问计算机内存的技术,说白了就是给 CPU 打工的,帮 CPU 干一些搬运数据的简单工作。

CPU 告诉 DMA 自己需要哪些数据,然后 DMA 负责搬运到 PageCache,等搬运完成后,DMA 控制器再通过中断通知 CPU,这样就极大地节省了 CPU 的资源。

但如果要读取的内容已经命中 PageCache,那么这一步可以省略。

3)将文件内容从 PageCache 拷贝到用户空间中,因为应用程序在用户空间,磁盘数据必须从内核空间搬运到用户空间,应用程序才能操作它。注意:这一步的数据搬运不再由 DMA 负责,而是由 CPU 负责。

因为 DMA 主要用于硬件设备与内存之间的数据传输,例如从磁盘到 RAM,从 RAM 到网卡。虽然 DMA 可以减少 CPU 的负担,但通常不用于内核空间和用户空间之间的数据搬运,至于原因也很简单:

  • 操作系统需要保护内核空间,防止用户程序直接访问,以维护系统的安全和稳定。通过 CPU 进行数据拷贝,操作系统可以控制哪些数据和资源可以被用户程序访问。
  • CPU 可以处理复杂的逻辑和任务调度,更适合执行这种涉及系统安全和资源管理的任务。
  • 在数据从内核空间传输到用户空间的过程中,可能需要进行一些额外的处理,例如格式转换、权限检查等,这些都是 CPU 更擅长的。

另外用户空间和内核空间的切换,本质上就是 CPU 的执行上下文和权限级别发生了改变。

因此这一步会涉及用户态和内核态之间的切换,和一个数据的拷贝。

4) 文件内容读取之后,要通过网络发送给消费者客户端。而内核提供了一个 Socket 缓冲区,位于用户空间的应用程序在发送数据时,会先通过 CPU 将数据拷贝到内核空间的 Socket 缓冲区中,再由内核通过网卡发送给消费者。

同样的,当数据从网络到达时,也会先被放在 Socket 缓冲区中。应用程序从该缓冲区读取数据,数据被拷贝到用户空间。

所以应用程序在通过网络收发数据时,其实都是在和 Socket 缓冲区打交道,具体的发送和接收任务都是由内核来做的,因为只有内核才能操作硬件设备。用户空间的代码要想与硬件设备交互,必须通过系统调用或操作系统提供的其它接口,然后由内核代为执行。

所以通过网络发送数据,会涉及一次数据的拷贝,以及用户空间和内核空间的切换。因为 CPU 要将数据从用户空间搬运到内核空间的 Socket 缓冲区中。

5) 内核要将 Socket 缓冲区里的数据通过网卡发送出去,于是再将数据从 Socket 缓冲区搬到网卡的缓冲区里面,而这一步搬运是由 DMA 来做的。只要不涉及用户空间,大部分的数据搬运都可以由 DMA 来做,而一旦涉及到用户空间,数据搬运就必须由 CPU 来做。

6) 发送完毕之后,再从内核空间切换到用户空间,应用程序继续干其它事情。

如果想要提升性能,那么关键就在于减少上下文切换的次数和数据拷贝的次数,因为用户空间和内核空间的切换是需要成本的,至于数据拷贝就更不用说了。

而整个过程涉及了 4 次的上下文切换,因为用户空间没有权限操作磁盘或网卡,这些操作都需要交由操作系统内核来完成。而通过内核去完成某些任务的时候,需要使用操作系统提供的系统调用函数。而一次系统调用必然会发生两次上下文切换:首先从用户态切换到内核态,当内核执行完任务后,再切换回用户态交由应用程序执行其它代码。

然后是数据拷贝,这个数据也被拷贝了 4 次,其中两次拷贝由 DMA 负责,另外两次由 CPU 负责。但很明显,CPU 的两次拷贝没有太大必要,先将数据从 PageCache 拷贝到用户空间,然后再从用户空间拷贝到 Socket 缓冲区。既然这样的话,那直接从 PageCache 拷贝到 Socket 缓冲区不行吗。

如果文件在读取之后不对它进行操作,或者说不对文件数据进行加工,只是单纯地通过网卡发送出去,那么就没必要到用户空间这里绕一圈。

为什么 Kafka 的吞吐量那么高?

此时的 4 次上下文切换就变成了 2 次,因为系统调用只有 1 次。数据搬运也由 4 次变成了 3 次,所以总共减少了两次上下文切换和一次数据拷贝。

而这种减少数据拷贝(特别是在用户和内核之间的数据拷贝)的技术,便称之为零拷贝。

Linux 内核提供了一个系统调用函数 sendfile(),便可以实现上面这个过程。

#include <sys/sendfile.h>

ssize_t sendfile(int out_fd, int in_fd, 
                 off_t *offset, size_t count);

out_fd 和 in_fd 均为文件描述符,分别代表要写入的文件和要读取的文件,offset 表示从文件的哪个位置开始读,count 表示写入多少个字节。返回值是实际写入的长度。

当然像 Python/ target=_blank class=infotextkey>Python、JAVA 都对 sendfile 进行了封装,我们在使用 Python 进行 Socket 编程时,便可以使用该方法。

为什么 Kafka 的吞吐量那么高?

当然该方法会调用 os.sendfile(),它和 C 的 sendfile() 是一致的,如果是 Linux 系统,那么不存在问题。如果是 windows 系统,os.sendfile() 则不可用,此时 Socket 的 sendfile 会退化为 send 方法。

然而目前来说,虽然实现了零拷贝,但还不是零拷贝的终极形态。我们看到 CPU 还是进行了一次拷贝,并且此时虽然不涉及用户空间,但数据搬运依旧是 CPU 来做的。因为 DMA 主要负责硬件(例如磁盘或网卡)和内存的数据传输,但不适用于内存到内存的数据拷贝。

那么问题来了,数据文件从磁盘读到 PageCache 之后,可不可以直接搬到网卡缓冲区里面呢?如果你的网卡支持 SG-DMA 技术,那么通过 CPU 将数据从 PageCache 拷贝到 socket 缓冲区这一步也可以省略。

你可以通过以下命令,查看网卡是否支持 SG(scatter-gather)特性:

[root@satori ~]# ethtool -k eth0 | grep scatter-gather
scatter-gather: on
 tx-scatter-gather: on
 tx-scatter-gather-fraglist: off [fixed]

Linux 内核从 2.4 版本开始起,对于那些支持 SG-DMA 技术的网卡,会进一步优化 sendfile() 系统调用的过程,优化后的过程如下:

  • DMA 将数据从磁盘拷贝到 PageCache;
  • 将描述符和数据长度发送到 Socket 缓冲区,网卡的 SG-DMA 控制器基于该信息直接将 PageCache 的数据拷贝到网卡缓冲区中;

整个过程如下:

为什么 Kafka 的吞吐量那么高?

此时便是零拷贝(Zero-copy)技术的终极形态,因为我们没有在内存层面去拷贝数据,也就是说全程没有通过 CPU 来搬运数据,所有的数据都是通过 DMA 来进行传输的。

使用零拷贝技术只需要两次上下文切换和数据拷贝,就可以完成文件的传输,因为它通过一次系统调用(sendfile 方法)将磁盘读取与网络发送两个操作给合并了,从而降低了上下文切换次数。而且两次的数据拷贝过程也不需要通过 CPU,都是由 DMA 来搬运。所以总体来看,零拷贝技术可以把文件传输的性能提高至少一倍以上。

但需要注意的是,零拷贝技术不允许进程对文件内容作进一步加工,比如压缩数据再发送。如果希望对读取的文件内容做额外的操作,那么就只能拷贝到用户空间了。

另外当传输大文件时,不建议使用零拷贝,因为 PageCache 可能被大文件占据,而导致「热点」小文件无法利用到 PageCache,并且大文件的缓存命中率也不高,因此这种情况建议绕过 PageCache。

使用 PageCache 的 IO 叫做缓存 IO,不使用 PageCache 的 IO 叫做直接 IO。

小结

以上我们就探讨了 Kafka 为什么会有如此高的吞吐量,在处理海量数据时为什么这么快。核心就在于以下几点:

1)消息是以 "批" 为单位的。

2)利用磁盘的顺序读写远远快于随机读写。

3)使用 PageCache。

4)使用零拷贝技术。



Tags:Kafka   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
Spring实现Kafka重试Topic,真的太香了
概述Kafka的强大功能之一是每个分区都有一个Consumer的偏移值。该偏移值是消费者将读取的下一条消息的值。可以自动或手动增加该值。如果我们由于错误而无法处理消息并想重...【详细内容】
2024-01-26  Search: Kafka  点击:(84)  评论:(0)  加入收藏
如何使用Python、Apache Kafka和云平台构建健壮的实时数据管道
译者 | 李睿审校 | 重楼在当今竞争激烈的市场环境中,为了生存和发展,企业必须能够实时收集、处理和响应数据。无论是检测欺诈、个性化用户体验还是监控系统,现在都需要接近即时...【详细内容】
2024-01-26  Search: Kafka  点击:(46)  评论:(0)  加入收藏
深入浅出Kafka:高可用、顺序消费及幂等性
在我们旅行于数据海洋的途中,如果把 Kafka 比作是一艘承载无数信息航行的快船,前文《Kafka实战漫谈:大数据领域的不败王者》已经讲述了如何搭建起这艘快船,让它在起风的早晨开始...【详细内容】
2023-12-18  Search: Kafka  点击:(172)  评论:(0)  加入收藏
7k Star,一款开源的 Kafka 管理平台,功能齐全、页面美观!
Apache Kafka UI 是一个免费的开源 Web UI,用于监控和管理 Apache Kafka 集群,可方便地查看 Kafka Brokers、Topics、消息、Consumer 等情况,支持多集群管理、性能监控、访问控...【详细内容】
2023-12-15  Search: Kafka  点击:(128)  评论:(0)  加入收藏
利用Apache Kafka、Flink和Druid构建实时数据架构
译者 | 陈峻审校 | 重楼如今,对于使用批处理工作流程的数据团队而言,要满足业务的实时要求并非易事。从数据的交付、处理到分析,整个批处理工作流往往需要大量的等待,其中包括:等...【详细内容】
2023-12-11  Search: Kafka  点击:(227)  评论:(0)  加入收藏
运维兄弟!Kafka怎么又"超时"了?
现象凌晨,当运维刚躺下,就被业务研发的电话叫醒,"哥们!kafka服务又异常了?影响到业务了,快看看",业务研发给出的异常日志如下:基本分析 集群检查:立即确认kafka集群以及涉及到topic健...【详细内容】
2023-12-07  Search: Kafka  点击:(137)  评论:(0)  加入收藏
图解Kafka适用场景,全网最全!
消息系统消息系统被用于各种场景,如解耦数据生产者,缓存未处理的消息。Kafka 可作为传统的消息系统的替代者,与传统消息系统相比,kafka有更好的吞吐量、更好的可用性,这有利于处...【详细内容】
2023-11-29  Search: Kafka  点击:(183)  评论:(0)  加入收藏
Kafka有哪些应用场景?你能说上来几个?
下面我们来总结一下Kafka的一些应用场景:1、日志处理与分析(最常用的场景)下图显示了典型的 ELK(Elastic-Logstash-Kibana)堆栈。Kafka 有效地从每个实例收集日志流。ElasticSe...【详细内容】
2023-11-28  Search: Kafka  点击:(163)  评论:(0)  加入收藏
Kafka:解锁大数据时代的搜索与分析
在当今大数据时代,数据湖作为一种新兴的数据存储和分析解决方案,正受到越来越多企业的青睐。而作为一种高性能、可扩展的事件流平台,Kafka在数据湖领域发挥着重要的作用。本文...【详细内容】
2023-11-24  Search: Kafka  点击:(287)  评论:(0)  加入收藏
解密Kafka主题的分区策略:提升实时数据处理的关键
Kafka几乎是当今时代背景下数据管道的首选,无论你是做后端开发、还是大数据开发,对它可能都不陌生。开源软件Kafka的应用越来越广泛。面对Kafka的普及和学习热潮,哪吒想分享一...【详细内容】
2023-11-21  Search: Kafka  点击:(179)  评论:(0)  加入收藏
▌简易百科推荐
即将过时的 5 种软件开发技能!
作者 | Eran Yahav编译 | 言征出品 | 51CTO技术栈(微信号:blog51cto) 时至今日,AI编码工具已经进化到足够强大了吗?这未必好回答,但从2023 年 Stack Overflow 上的调查数据来看,44%...【详细内容】
2024-04-03    51CTO  Tags:软件开发   点击:(5)  评论:(0)  加入收藏
跳转链接代码怎么写?
在网页开发中,跳转链接是一项常见的功能。然而,对于非技术人员来说,编写跳转链接代码可能会显得有些困难。不用担心!我们可以借助外链平台来简化操作,即使没有编程经验,也能轻松实...【详细内容】
2024-03-27  蓝色天纪    Tags:跳转链接   点击:(12)  评论:(0)  加入收藏
中台亡了,问题到底出在哪里?
曾几何时,中台一度被当做“变革灵药”,嫁接在“前台作战单元”和“后台资源部门”之间,实现企业各业务线的“打通”和全域业务能力集成,提高开发和服务效率。但在中台如火如荼之...【详细内容】
2024-03-27  dbaplus社群    Tags:中台   点击:(8)  评论:(0)  加入收藏
员工写了个比删库更可怕的Bug!
想必大家都听说过删库跑路吧,我之前一直把它当一个段子来看。可万万没想到,就在昨天,我们公司的某位员工,竟然写了一个比删库更可怕的 Bug!给大家分享一下(不是公开处刑),希望朋友们...【详细内容】
2024-03-26  dbaplus社群    Tags:Bug   点击:(5)  评论:(0)  加入收藏
我们一起聊聊什么是正向代理和反向代理
从字面意思上看,代理就是代替处理的意思,一个对象有能力代替另一个对象处理某一件事。代理,这个词在我们的日常生活中也不陌生,比如在购物、旅游等场景中,我们经常会委托别人代替...【详细内容】
2024-03-26  萤火架构  微信公众号  Tags:正向代理   点击:(10)  评论:(0)  加入收藏
看一遍就理解:IO模型详解
前言大家好,我是程序员田螺。今天我们一起来学习IO模型。在本文开始前呢,先问问大家几个问题哈~什么是IO呢?什么是阻塞非阻塞IO?什么是同步异步IO?什么是IO多路复用?select/epoll...【详细内容】
2024-03-26  捡田螺的小男孩  微信公众号  Tags:IO模型   点击:(8)  评论:(0)  加入收藏
为什么都说 HashMap 是线程不安全的?
做Java开发的人,应该都用过 HashMap 这种集合。今天就和大家来聊聊,为什么 HashMap 是线程不安全的。1.HashMap 数据结构简单来说,HashMap 基于哈希表实现。它使用键的哈希码来...【详细内容】
2024-03-22  Java技术指北  微信公众号  Tags:HashMap   点击:(11)  评论:(0)  加入收藏
如何从头开始编写LoRA代码,这有一份教程
选自 lightning.ai作者:Sebastian Raschka机器之心编译编辑:陈萍作者表示:在各种有效的 LLM 微调方法中,LoRA 仍然是他的首选。LoRA(Low-Rank Adaptation)作为一种用于微调 LLM(大...【详细内容】
2024-03-21  机器之心Pro    Tags:LoRA   点击:(12)  评论:(0)  加入收藏
这样搭建日志中心,传统的ELK就扔了吧!
最近客户有个新需求,就是想查看网站的访问情况。由于网站没有做google的统计和百度的统计,所以访问情况,只能通过日志查看,通过脚本的形式给客户导出也不太实际,给客户写个简单的...【详细内容】
2024-03-20  dbaplus社群    Tags:日志   点击:(4)  评论:(0)  加入收藏
Kubernetes 究竟有没有 LTS?
从一个有趣的问题引出很多人都在关注的 Kubernetes LTS 的问题。有趣的问题2019 年,一个名为 apiserver LoopbackClient Server cert expired after 1 year[1] 的 issue 中提...【详细内容】
2024-03-15  云原生散修  微信公众号  Tags:Kubernetes   点击:(6)  评论:(0)  加入收藏
站内最新
站内热门
站内头条