Kafka中的日志存储
阅读以下内容你将了解到:
1.日志的简单介绍
2.消息的压缩
3.日志索引
4.日志的清理方式
5.Kafka为什么快?(包括顺序I/O、页缓存、磁盘I/O算法的选择、零拷贝)
1.日志的简单介绍
Kafka的消息是存储在磁盘上,即日志中的。日志(Log)又分为多个LogSegment,以便于消息的维护和清理。而Log中追加消息的时候是顺序写入的,这也大大加快了I/O 的速度,每个LogSegment又有对应的两个索引文件:偏移量索引和时间戳索引。
2.消息的压缩
Kafka会将多条消息一起进行压缩。一般情况下生产者是保持压缩状态进行存储的,消费者从服务端获得的也是压缩的数据,只有在处理消息前才会解压消息。支持以下三种压缩算法:GZIP、SNAPPY、LZ4.
3.日志索引
Kafka中的索引文件以稀疏索引的方式构成,使用二分法来快速定位偏移量的位置,如果偏移量不在索引中,那么会返回小于指定偏移量的最大偏移量。
4.日志的清理方式
日志删除:基于时间、日志的大小或者日志的偏移量来删除前面一部分日志。
日志压缩:可以类比Redis中的RDB模式,对于有相同key的value,只保留最后一个版本
关于日志压缩:引入一个新的概念,“墓碑消息”——指的是key不为null,而value为null的消息。在第二次压缩开始时就会清除墓碑消息,还会把细碎的文件合并成大文件。
5.Kafka为什么快?
1.顺序I/O
2.页缓存的使用
3.磁盘I/O的算法选择
4.零拷贝
接下来我们会一一来介绍这几点。
1.顺序I/O
image.png
Kafka在设计时采用了文件追加的方式来写入消息,上图是一个磁盘和内存的I/O速度比较,由此可见一斑。
2.页缓存
具体来说就是把磁盘中的数据缓存到内存中,当进程准备读取磁盘时,会先查看内存里是否存在,存在即返回数据,不存在会从磁盘读取后放到页缓存中。
当进程准备写入磁盘时,先在内缓存中添加相应的页,最后将数据写入对应的页,操作系统会在合适的时间把脏页中的数据写到磁盘中,以保持数据的一致性。
即时Kafka重启,页缓存还是会保持有效
3.磁盘I/O的算法选择
NOOP:所有I/O请求大致按照先来后到(FIFO)的顺序进行操作。
CFQ:按照I/O的地址进行排序。(先来的I/O不一定能被满足,可能会被"饿死")
DEADLINE:在CFQ的基础上解决了饿死的情况,此算法额外添加了读I/O(最大等待时间500ms),写I/O(最大等待时间5s)的FIFO队列,优先级表示如下:FIFO(Read)>FIFO(Write)>CFQ
ANTICIPATORY: CFQ与DEADLINE只考虑了零散I/O,此算法在此基础上优化了顺序I/O。在DEADLINE的基础上,为每个I/O设置了6ms的等待窗口,如果在6ms内OS收到了相邻位置的读I/O请求,就可立即满足。
建议对于不同的业务需求来测试并选择合适的磁盘调度算法。
4.零拷贝
所谓零拷贝是指将数据直接从磁盘文件复制到网卡设备中。
零拷贝 将文件复制到内核模式下的ReadBuffer,DMA引擎将数据从内核引擎模式中传递到网卡设备。
对比非零拷贝,减少了将内核复制到用户态,再从用户态复制回内核这两步操作。强无敌。直接上图
image.png