首页 > 编程知识 正文

kafka原理详解图文,kafka底层原理

时间:2023-05-03 10:08:48 阅读:33258 作者:2003

目录

前言: Kafka为什么那么快((高效) ) )。

1 .文件系统

2 .降低时间复杂度

3 .零拷贝

4 .下一节预告

前言: Kafka为什么那么快、高效地利用磁盘顺序写入的优点进行预读后再进行写入? 最大限度地减少使用内存缓存打包邮件,最大限度地减少大量小型IO操作的影响。 用于读写基于mmap的索引和日志的TransportLayer .文件系统Kafka的消息存储和缓存很大程度上依赖于文件系统。 “磁盘速度慢”的图像很常见,但实际上磁盘速度比预期的慢,而且速度快。 这取决于磁盘的使用方式。

使用6个7200rpm、SATA接口和RAID-5的磁盘阵列在JBOD配置中的顺序写入性能约为600MB/秒,而随机写入性能约为100k/秒,相差6000倍以上。

的线性读写是磁盘使用模式中最规则的,并经过操作系统极大优化。

读头以大数据块为单位预读数据

write-behind是将多个小逻辑写入整合到一个大物理磁盘写入中

有关此问题的进一步讨论,请参见ACM Queue article。 他们实际上发现顺序磁盘访问在某些情况下比随机内存访问更快!

为了弥补这种性能差异,现代操作系统主动将所有空闲内存用作 disk caching(磁盘高速缓存),所有对磁盘的读写操作都会通过这个统一的 cache( in-process cache)。

即使该进程保留一个in-process cache,该数据也可能被复制到操作系统的pagecache中,实际上它包含两个内容。

此外,Kafka构建在JVM之上,有两点是任何知道使用Java内存的人都知道的。

的内存开销非常高,通常是存储数据的两倍多。

随着堆中数据的增加,Java垃圾回收越来越复杂和慢。

kafka选择了非常简单的设计。 与尽可能多地维护内存缓存,并在空间不足时将数据快速刷新到文件系统相比,这一过程正好相反。所有数据一开始就被写入到文件系统的持久化日志中,而不用在 cache 空间不足的时候 flush 到磁盘实际上,这表明数据已转移到内核的pagecache。

页面缓存

Page cache(页面缓存)

Page cache (也称为页面缓冲区或文件缓冲区)由许多磁盘块组成。 大小通常为4k,在64位系统中为8k,配置的一些磁盘块在物理磁盘上不一定是连续的。 文件的组织单位是一页,即一个Page cache大小,从外部存储器中的几个不连续磁盘块读取文件到buffer cache

Buffer cache(块缓存)

Buffer cache (也称为块缓冲区)缓冲物理磁盘上的一个磁盘块,通常大小为1k,磁盘块也是磁盘的组织单元。 buffer cache的设置是为了在程序多次访问同一磁盘块时减少访问时间。

Page cache(页面缓存)与Buffer cache(块缓存)的区别

的操作包括逻辑级别(文件系统)和物理级别(磁盘块),这两种类型的缓存分别缓存逻辑级别和物理级别的数据。

在文件系统上处理文件时,文件将缓存在Page Cache中,如果需要更新文件,请使用Page C

ache将交给Buffer Cache去完成,因为Buffer Cache就是缓存磁盘块的。

简单说来,page cache用来缓存文件数据,buffer cache用来缓存磁盘数据。在有文件系统的情况下,对文件操作,那么数据会缓存到page cache,如果直接采用dd等工具对磁盘进行读写,那么数据会缓存到buffer cache。

Buffer(Buffer Cache)以块形式缓冲了块设备的操作,定时或手动的同步到硬盘,它是为了缓冲写操作然后一次性将很多改动写入硬盘,避免频繁写硬盘,提高写入效率。

Cache(Page Cache)以页面形式缓存了文件系统的文件,给需要使用的程序读取,它是为了给读操作提供缓冲,避免频繁读硬盘,提高读取效率。

2.降低时间复杂度

        消息系统使用的持久化数据结构通常是和 BTree 相关联的消费者队列或者其他用于存储消息源数据的通用随机访问数据结构。BTree 的操作复杂度是 O(log N),通常我们认为 O(log N) 基本等同于常数时间,但这条在磁盘操作中不成立。

        存储系统将非常快的cache操作和非常慢的物理磁盘操作混合在一起,当数据随着 fixed cache 增加时,可以看到树的性能通常是非线性的——比如数据翻倍时性能下降不只两倍。

        kafka选择把持久化队列建立在简单的读取和向文件后追加两种操作之上,这和日志解决方案相同。这种架构的优点在于所有的操作复杂度都是O(1),而且读操作不会阻塞写操作,读操作之间也不会互相影响。

        在不产生任何性能损失的情况下能够访问几乎无限的硬盘空间,Kafka 可以让消息保留相对较长的一段时间(比如一周),而不是试图在被消费后立即删除。

        降低大量小型IO操作的影响

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

        为了避免这种情况,kafka的协议是建立在一个 “消息块” 的抽象基础上,合理将消息分组。将多个消息打包成一组,而不是每次发送一条消息,从而使整组消息分担网络中往返的开销。

        这个简单的优化对速度有着数量级的提升。批处理允许更大的网络数据包,更大的顺序读写磁盘操作,连续的内存块等等,所有这些都使 KafKa 将随机流消息顺序写入到磁盘, 再由 consumers 进行消费。

3.零拷贝

        字节拷贝是低效率的操作,在消息量少的时候没啥问题,但是在高负载的情况下,影响就不容忽视。为了避免这种情况,kafka使用 producer ,broker 和 consumer 都共享的标准化的二进制消息格式,这样数据块不用修改就能在他们之间传递。

保持这种通用格式可以对一些很重要的操作进行优化: 持久化日志块的网络传输。现代的unix 操作系统提供了一个高度优化的编码方式,用于将数据从 pagecache 转移到 socket 网络连接中;在 Linux 中系统调用 sendfile 做到这一点。

传统IO (4次上下文切换4次拷贝)

假如将磁盘上的文件读取出来,然后通过网络协议发送给客户端。

一般需要两个系统调用,但是一共4次上下文切换,4次拷贝

read(file, tmp_buf, len);write(socket, tmp_buf, len);

要想提高文件传输的性能,就需要减少「用户态与内核态的上下文切换」和「内存拷贝」的次数

mmap(4次上下文切换3次拷贝)

mmap()系统调用函数会直接把内核缓冲区里的数据「映射」到用户空间,这样,操作系统内核与用户空间就不需要再进行任何的数据拷贝操作,它替换了read()系统调用函数。

buf = mmap(file, len);write(sockfd, buf, len);

sendfile(2次上下文切换3次拷贝

Linux 内核版本 2.1 中,提供了一个专门发送文件的系统调用函数 sendfile()

首先,它可以替代前面的 read()和 write()这两个系统调用,这样就可以减少一次系统调用,也就减少了 2 次上下文切换的开销。

其次,该系统调用,可以直接把内核缓冲区里的数据拷贝到 socket 缓冲区里,不再拷贝到用户态,这样就只有 2 次上下文切换,和 3 次数据拷贝。

#include <sys/socket.h>ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

它的前两个参数分别是目的端和源端的文件描述符,后面两个参数是源端的偏移量和复制数据的长度,返回值是实际复制数据的长度。

零拷贝(2次上下文切换2次拷贝)

Linux 内核 2.4 版本开始起,对于支持网卡支持 SG-DMA 技术的情况下, sendfile() 系统调用的过程发生了点变化,具体过程如下:

第一步,通过 DMA 将磁盘上的数据拷贝到内核缓冲区里;

第二步,缓冲区描述符和数据长度传到 socket 缓冲区,这样网卡的 SG-DMA 控制器就可以直接将内核缓存中的数据拷贝到网卡的缓冲区里,此过程不需要将数据从操作系统内核缓冲区拷贝到 socket 缓冲区中,这样就减少了一次数据拷贝;

4.下一节预告 kafka高效文件存储设计特点推荐阅读 深入浅出kafka原理-1-初识只作乍见之欢深入浅出kafka原理-2-Kafka为何那么快(高效)深入浅出kafka原理-3-高效文件存储设计特点深入浅出kafka原理-4-kafka网络机制原理

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。