背地的关键要素-Kafka-揭秘-惊人的吞吐量 (背地是什么意思?)
在泛滥的信息两边件中,Kafka的性能和吞吐量相对是顶尖级别的,那么疑问来了,Kafka是如何做到高吞吐的。在性能优化方面,它经常使用了哪些技巧呢?上方咱们就来剖析一下。
以'批'为单位
批量处置是一种十分有效的优化系统吞吐量的方法,操作系统提供的缓冲区也是如此。在Kafka外部,信息处置是以"批"为单位的,消费者、Broker、消费者,都是如此。
在Kafka的客户端SDK中,消费者只提供了单条发送的send()方法,并没有提供任何批量发送的接口。要素是Kafka基本就没有提供单条发送的配置,是的你没有看错,只管它提供的API每次只能发送一条信息,但实践上Kafka的客户端SDK在成功信息发送逻辑的时刻,驳回了异步批量发送的机制。
当你调用send()方法发送一条信息之后,无论你是同步发送还是异步发送,Kafka都不会立刻就把这条信息发送进来。它会先把这条信息,寄存在内存中缓存起来,而后选用适宜的机遇把缓存中的一切信息组成一批,一次性性发给Broker。繁难地说,就是攒一波一同发。
而KafkaBroker在收到这一批信息后,也不会将其恢复成多条信息、再一条一条地处置,这样太慢了。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的内容,但实践读取的却并不止1M,由于这样你后续再读取的时刻就不须要从磁盘上加载了。由于从磁盘到内存的数据传输速度是很慢的,假设物理内存有空余,那么就可以多缓存一些内容。
而Kafka在读写信息文件的时刻,充沛应用了PageCache的特性。普通来说,信息刚刚写入到服务端就会被消费,读取的时刻,关于这种刚刚写入的PageCache,命中的几率会十分高。也就是说,大局部状况下,消费读信息都会命中PageCache,带来的好处有两个:一个是读取的速度会十分快,另外一个是,给写入信息让出磁盘的IO资源,直接也优化了写入的性能。
ZeroCopy(零拷贝)
Kafka还经常使用了零拷贝技术,首先Broker将信息发送给消费者的环节如下:
这个环节会阅历几次复制,以及用户空间和内核空间的切换,示用意如下。
整个环节大略是以上6个步骤,咱们区分解释一下。
运行程序要读取磁盘文件,但只要内核才干操作配件设备,所以此时会从用户空间切换到内核空间。
经过DMA将文件读到PageCache中,此时的数据拷贝是由DMA来做的,不消耗CPU。关于DMA,它是一种准许配件系统访问计算机内存的技术,说白了就是给CPU打工的,帮CPU干一些搬运数据的繁难上班。
CPU通知DMA自己须要哪些数据,而后DMA担任搬运到PageCache,等搬运成功后,DMA控制器再经过终止通知CPU,这样就极大地节俭了CPU的资源。
但假设要读取的内容曾经命中PageCache,那么这一步可以省略。
将文件内容从PageCache拷贝到用户空间中,由于运行程序在用户空间,磁盘数据肯定从内核空间搬运到用户空间,运行程序才干操作它。留意:这一步的数据搬运不再由DMA担任,而是由CPU担任。
由于DMA关键用于配件设备与内存之间的数据传输,例如从磁盘到RAM,从RAM到网卡。只管DMA可以缩小CPU的累赘,但通常不用于内核空间和用户空间之间的数据搬运,至于要素也很繁难:
另外用户空间和内核空间的切换,实质上就是CPU的口头高低文和权限级别出现了扭转。
因此这一步会触及用户态和内核态之间的切换,和一个数据的拷贝。
文件内容读取之后,要经过网络发送给消费者客户端。而内核提供了一个Socket缓冲区,位于用户空间的运行程序在发送数据时,会先经过CPU将数据拷贝到内核空间的Socket缓冲区中,再由内核经过网卡发送给消费者。
雷同的,当数据从网络抵达时,也会先被放在Socket缓冲区中。运行程序从该缓冲区读取数据,数据被拷贝到用户空间。
所以运行程序在经过网络收发数据时,其实都是在和Socket缓冲区打交道,详细的发送和接纳义务都是由内核来做的,由于只要内核才干操作配件设备。用户空间的代码要想与配件设备交互,肯定经过系统调用或操作系统提供的其它接口,而后由内核代为口头。
所以经过网络发送数据,会触及一次性数据的拷贝,以及用户空间和内核空间的切换。由于CPU要将数据从用户空间搬运到内核空间的Socket缓冲区中。
内核要将Socket缓冲区里的数据经过网卡发送进来,于是再将数据从Socket缓冲区搬到网卡的缓冲区外面,而这一步搬运是由DMA来做的。只需不触及用户空间,大局部的数据搬运都可以由DMA来做,而一旦触及到用户空间,数据搬运就肯定由CPU来做。
发送终了之后,再从内核空间切换到用户空间,运行程序继续干其它事情。
假构想要优化性能,那么关键就在于缩小高低文切换的次数和数据拷贝的次数,由于用户空间和内核空间的切换是须要老本的,至于数据拷贝就更不用说了。
而整个环节触及了4次的高低文切换,由于用户空间没有权限操作磁盘或网卡,这些操作都须要交由操作系统内核来成功。而经过内核去成功某些义务的时刻,须要经常使用操作系统提供的系统调用函数。而一次性系统调用肯定会出现两次高低文切换:首先从用户态切换到内核态,当内核口头完义务后,再切换回用户态交由运行程序口头其它代码。
而后是数据拷贝,这个数据也被拷贝了4次,其中两次拷贝由DMA担任,另外两次由CPU担任。但很显著,CPU的两次拷贝没有太大必要,先将数据从PageCache拷贝到用户空间,而后再从用户空间拷贝到Socket缓冲区。既然这样的话,那直接从PageCache拷贝到Socket缓冲区不行吗。
假设文件在读取之后不对它启动操作,或许说不对文件数据启动加工,只是单纯地经过网卡发送进来,那么就没必要到用户空间这里绕一圈。
此时的4次高低文切换就变成了2次,由于系统调用只要1次。数据搬运也由4次变成了3次,所以总共缩小了两次高低文切换和一次性数据拷贝。
而这种缩小数据拷贝(特意是在用户和内核之间的数据拷贝)的技术,便称之为零拷贝。
Linux内核提供了一个系统调用函数sendfile(),便可以成功上方这个环节。
#include<sys/sendfile.h>ssize_tsendfile(intout_fd,intin_fd,off_t*offset,size_tcount);
out_fd和in_fd均为文件形容符,区分代表要写入的文件和要读取的文件,offset表示从文件的哪个位置开局读,count表示写入多少个字节。前往值是实践写入的长度。
当然像/target=_blankclass=infotextkey>Python、都对sendfile启动了封装,咱们在经常使用Python启动Socket编程时,便可以经常使用该方法。
当然该方法会调用os.sendfile(),它和C的sendfile()是分歧的,假设是Linux系统,那么不存在疑问。假设是系统,os.sendfile()则无法用,此时Socket的sendfile会退步为send方法。
但是目前来说,只管成功了零拷贝,但还不是零拷贝的终极外形。咱们看到CPU还是启动了一次性拷贝,并且此时只管不触及用户空间,但数据搬运照旧是CPU来做的。由于DMA关键担任配件(例如磁盘或网卡)和内存的数据传输,但不实用于内存到内存的数据拷贝。
那么疑问来了,数据文件从磁盘读到PageCache之后,可无法以直接搬到网卡缓冲区外面呢?假设你的网卡支持SG-DMA技术,那么经过CPU将数据从PageCache拷贝到socket缓冲区这一步也可以省略。
你可以经过以下命令,检查网卡能否支持SG(scatter-gather)特性:
[root@satori~]#ethtool-keth0|grepscatter-gatherscatter-gather:ontx-scatter-gather:ontx-scatter-gather-fraglist:off[fixed]
Linux内核从2.4版本开局起,关于那些支持SG-DMA技术的网卡,会进一步优化sendfile()系统调用的环节,优化后的环节如下:
整个环节如下:
此时便是零拷贝(Zero-copy)技术的终极外形,由于咱们没有在内存层面去拷贝数据,也就是说全程没有经过CPU来搬运数据,一切的数据都是经过DMA来启动传输的。
经常使用零拷贝技术只须要两次高低文切换和数据拷贝,就可以成功文件的传输,由于它经过一次性系统调用(sendfile方法)将磁盘读取与网络发送两个操作给兼并了,从而降落了高低文切换次数。而且两次的数据拷贝环节也不须要经过CPU,都是由DMA来搬运。所以总体来看,零拷贝技术可以把文件传输的性能提高至少一倍以上。
但须要留意的是,零拷贝技术不准许进程对文件内容作进一步加工,比如紧缩数据再发送。假设宿愿对读取的文件内容做额外的操作,那么就只能拷贝到用户空间了。
另外当传输大文件时,不倡导经常使用零拷贝,由于PageCache或许被大文件占据,而造成「热点」小文件无法应用到PageCache,并且大文件的缓存命中率也不高,因此这种状况倡导绕过PageCache。
经常使用PageCache的IO叫做缓存IO,不经常使用PageCache的IO叫做直接IO。
小结
以上咱们就讨论了Kafka为什么会有如此高的吞吐量,在处置海量数据时为什么这么快。外围就在于以下几点:
1)信息是以"批"为单位的。
2)应用磁盘的顺序读写远远快于随机读写。
3)经常使用PageCache。
4)经常使用零拷贝技术。
2、kafka为何能实现每秒几十万的吞吐量
Kafka是高吞吐量低延迟的高并发、高性能的消息中间件,在大数据领域有广泛的应用。那他是如何做到这么高的吞吐量和高性能呢?
生产者通过多batch合并一个request 一次性发送broker提高吞吐量 。 每个Kafka服务端叫做一个broker,负责管理一台机器上的数据;每个topic拆分成多个partition,这样每个partition存储一部分数据并放在不同的broker上。这时候生产者如果生产一条消息,就建立连接然后发送数据,效率肯定不高。
Kafka会在生产者放一个内存缓冲区,当生产消息后,它会把同一个topic同一个partition的消息打包成一个batch。
这样就结束了吗?当然不是,如果生产者这边有多个topic,不同topic发送到同一个broker的数据是否可以合并呢?当然可以 如果客户端那边有2个topic,每个topic有个3个partition,那每个broker就会有2个partition。这时候我们完全可以将发送到同一个broker的batch一次发送。所以kafka将发送到同一个broker的batch打包成一个request发送,进一步提高了通信的效率。
首先kafka在接收到数据后都会写磁盘,但是我们都知道写磁盘性能会很差,所以它并不是直接写磁盘。操作系统本身有一层缓存叫做页缓存,相当于内存,所以kafka是把数据写入到页缓存中,接下来由页缓存决定什么时候写入到磁盘。
普通机械磁盘如果随机写的话,性能会非常差,Kafka采用磁盘顺序写的方式,仅仅将数据追加到文件末尾,这种方式性能基本可以和内存媲美。
上面说的是kafka写入数据的优秀设计,那从磁盘读数据分发又是如何设计的呢?
我们可以想想分发数据一般是如何做的。首先肯定是从磁盘中读出数据到页缓存,然后从页缓存中拷贝到kafka中,然后再从kafka中拷贝到socket中,最后再给网卡。 而零拷贝技术,就是去除上面2步拷贝,直接从页缓存中将数据发送到网卡中,socket中仅仅只是拷贝一个描述符,这个过程大大提升了读取的性能。而且从磁盘读数据时候会先看看页缓存中有没有,如果有的话都不用读磁盘了。
kafka的特点
Kafka是一种高吞吐量的分布式发布-订阅消息系统,它主要设计用于处理大量数据的实时流处理。 Kafka的主要特点包括:1. 分布式:Kafka是一个分布式系统,可以部署在多台机器上,以处理大量数据。 2. 发布-订阅模型:Kafka支持发布-订阅消息模型,这意味着消息可以从一个或多个生产者发送到多个或一个消费者。 3. 高吞吐量:Kafka能够处理大量的数据,其吞吐量可以达到数千个消息每秒。 4. 持久性:Kafka保证了消息的持久性,即使在系统故障的情况下,消息也不会丢失。 5. 可扩展性:Kafka具有可扩展性,可以很容易地添加更多的节点以提高系统容量。 6. 易于使用:Kafka的使用相对简单,开发者可以快速上手并处理实时数据流。 以上特点使得Kafka在许多场景中都得到了广泛的应用,例如日志收集和处理、实时分析、实时数据流应用等。
免责声明:本文转载或采集自网络,版权归原作者所有。本网站刊发此文旨在传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及版权、内容等问题,请联系本网,我们将在第一时间删除。同时,本网站不对所刊发内容的准确性、真实性、完整性、及时性、原创性等进行保证,请读者仅作参考,并请自行核实相关内容。对于因使用或依赖本文内容所产生的任何直接或间接损失,本网站不承担任何责任。