kafka高性能原因分析(想到就写,持续更新,10/31):顺序读写、页缓存、零拷贝

1.顺序读写磁盘

  • 各个存储介质的速度层级

在这里插入图片描述

  • 顺序读写和随机读写对比

有关测试结果表明,一个由6块7200r/min的RAID-5阵列组成的磁盘簇的线性(顺序)写入速度可以达到600MB/s,而随机写入速度只有100KB/s,两者性能相差6000倍。操作系统可以针对线性读写做深层次的优化,比如预读(read-ahead,提前将一个比较大的磁盘块读入内存)和后写(write-behind,将很多小的逻辑写操作合并起来组成一个大的物理写操作)技术。顺序写盘的速度不仅比随机写盘的速度快,而且也比随机写内存的速度快
顺序写磁盘比随机写内存都快

在这里插入图片描述

  • kafka怎么做的

Kafka设计的时候采用了文件追加的方式写入消息,即只能在日志文件的尾部追加新的消息,并且也不允许修改已写入的消息,这就是典型的顺序写盘的操作

2.页缓存(把磁盘中的数据存到内存中,把对磁盘的操作变为对内存的访问)

  • 总体流程

当一个进程准备读取磁盘上的文件内容时,操作系统会先查看待读取的数据所在的页(page)是否在页缓存(pagecache)中,如果存在(命中)则直接返回数据,从而避免了对物理磁盘的 I/O 操作;如果没有命中,则操作系统会向磁盘发起读取请求并将读取的数据页存入页缓存,之后再将数据返回给进程。同样,如果一个进程需要将数据写入磁盘,那么操作系统也会检测数据对应的页是否在页缓存中,如果不存在,则会先在页缓存中添加相应的页,最后将数据写入对应的页。被修改过后的页也就变成了脏页,操作系统会在合适的时间把脏页中的数据写入磁盘,以保持数据的一致性。

  • 一些参数
1)vm.dirty_background_ratio:
用来指定当脏页数量达到系统内存的百分之多少之后就会触发 pdflush/flush/kdmflush 等后台回写进程的运行来处理脏页,一般设置为小于10的值即可,但不建议设置为0
2)vm.dirty_ratio
它用来指定当脏页数量达到系统内存的百分之多少之后就不得不开始对脏页进行处理,在此过程中,新的 I/O 请求会被阻挡直至所有脏页被冲刷到磁盘中
3)补充
对脏页有兴趣的读者还可以自行查阅vm.dirty_expire_centisecs、vm.dirty_writeback.centisecs等参数的使用说明。
  • 页缓存的优点
①利于节省JAVA程序进程的内部内存消耗
1)JAVA对象的内存开销非常大,通常会是真实数据大小的几倍甚至更多,空间使用率低下;Java的垃圾回收会随着堆内数据的增多
而变得越来越慢。基于这些因素,使用文件系统并依赖于页缓存的做法明显要优于维护一个进程内缓存或其他结构,至少我们可以省去
了一份进程内部的缓存消耗,同时还可以通过结构紧凑的字节码来替代使用对象的方式以节省更多的空间
②简化代码逻辑
2)此外,即使Kafka服务重启,页缓存还是会保持有效,然而进程内的缓存却需要重建。这样也极大地简化了代码逻辑,因为维护页缓存和文件之间的一致性交由操作系统来负责,这样会比进程内维护更加安全有效。
③pageCache交给操作系统异步落盘---
3)虽然消息都是先被写入页缓存,然后由操作系统负责具体的刷盘任务的,但在Kafka中同样提供了同步刷盘及间断性强制刷盘(fsync)的功能,这些功能可以通过log.flush.interval.messages、log.flush.interval.ms 等参数来控制。同步刷盘可以提高消息的可靠性,防止由于机器掉电等异常造成处于页缓存而没有及时写入磁盘的消息丢失。不过笔者并不建议这么做,刷盘任务就应交由操作系统去调配,消息的可靠性应该由多副本机制来保障,而不是由同步刷盘这种严重影响性能的行为来保障。
④swapping参数设置---
4)Linux系统会使用磁盘的一部分作为swap分区,这样可以进行进程的调度:把当前非活跃的进程调入 swap 分区,以此把内存空出
来让给活跃的进程。对大量使用系统页缓存的 Kafka而言,应当尽量避免这种内存的交换,否则会对它各方面的性能产生很大的负面影响。我们可以通过修改vm.swappiness参数(Linux系统参数)来进行调节。vm.swappiness参数的上限为 100,它表示积极地使用 
swap 分区,并把内存上的数据及时地搬运到 swap 分区中;vm.swappiness 参数的下限为0,表示在任何情况下都不要发生交换
(vm.swappiness=0的含义在不同版本的Linux 内核中不太相同,这里采用的是变更后的最新解释),这样一来,当内存耗尽时会根据
一定的规则突然中止某些进程。笔者建议将这个参数的值设置为 1,这样保留了swap的机制而又最大限度地限制了它对Kafka性能的影响。

3.零拷贝技术

  • 定义

将数据从磁盘文件复制到网卡设备中,而不需要经由应用程序,减少了内核态和用户态之间的上下文切换

  • 普通文件传输的过程
(1)调用read()时,文件A中的内容被复制到了内核模式下的Read Buffer中。
(2)CPU控制将内核模式数据复制到用户模式下。
(3)调用write()时,将用户模式下的内容复制到内核模式下的Socket Buffer中。
(4)将内核模式下的Socket Buffer的数据复制到网卡设备中传送。

在这里插入图片描述

说明:
从上面的过程可以看出,数据平白无故地从内核模式到用户模式“走了一圈”,浪费了 2次复制过程:第一次是从内核模式复制到用户模式;第二次是从用户模式再复制回内核模式,即上面4次过程中的第2步和第3步。而且在上面的过程中,内核和用户模式的上下文的切换也是4次。

  • 使用零拷贝之后

在这里插入图片描述
说明:
零拷贝技术通过DMA(Direct Memory Access)技术将文件内容复制到内核模式下的Read Buffer 中。不过没有数据被复制到 Socket Buffer,相反只有包含数据的位置和长度的信息的文件描述符被加到Socket Buffer中。DMA引擎直接将数据从内核模式中传递到网卡设备(协议引擎)。这里数据只经历了2次复制就从磁盘中传送出去了,并且上下文切换也变成了2次。零拷贝是针对内核模式而言的,数据在内核模式下实现了零拷贝。

猜你喜欢

转载自blog.csdn.net/weixin_43679037/article/details/121067247
今日推荐