如果对Kafka不了解的话,可以先看这篇博客《一文快速了解Kafka》。
其余有关Kakfa的文章如下:
每个Partition分为多个Segment,每个Segment有.log和.index两个文件。每个log文件记录具体的数据,每条消息都有一个递增的offset;Index文件是对log文件的索引。Consumer查找offset时使用的是二分法根据文件名去定位到Segment,然后解析msg,匹配到对应的offset的msg。
因为硬盘每次读写都会寻址和写入,其中寻址是一个耗时的操作。所以为了提高读写硬盘的速度,Kafka使用顺序I/O,来减少了寻址时间:收到消息后Kafka会把数据插入到文件末尾,每个消费者(Consumer)对每个Topic都有一个offset用来表示读取的进度。
因为顺序写入的特性,所以Kafka是无法删除数据的,它会将所有数据都保留下来。
为了优化读写性能,Kafka使用操作系统缓存——Page Cache,而不是JVM空间内存。
这样做的优势:
Page Cache配合mmap技术(直接内存映射),实现了用户态和内核态对指定内存区域的共享。
kafka基于sendfile实现零拷贝,数据不需要在应用程序做业务处理,仅仅是从一个DMA设备传输到另一个DMA设备。此时数据只需要复制到内核态,用户态不需要复制数据,然后发送网卡。
sendfile是Linux 2.1开始引入的,在Linux 2.4又做了一些优化:上图中磁盘页缓存中的数据,不需要复制到Socket缓冲区,而将数据的位置和长度信息存储到Socket缓冲区。实际数据是由DMA设备直接发送给对应的协议引擎,从而又减少了一次数据复制。
零拷贝并不是Kafka特有的机制,而是一种操作系统的底层支持,在NIO和Netty中都有应用,可以查看博客《NIO效率高的原理之零拷贝与直接内存映射》与《彻底搞懂Netty高性能之零拷贝》
Kafka支持多种压缩协议(包括Gzip和Snappy压缩协议),将消息进行批量压缩。
效果与Nginx压缩类似,都是牺牲部分CPU性能换取IO吞吐量的提升。
生产者发送多个消息到同一个分区的时候,为了减少网络带来的系能开销,kafka会对消息进行批量发送:
batch.size
:通过这个参数来设置批量提交的数据大小,默认是16k。当积压的同一分区的消息达到这个值的时候就会统一发送。linger.ms
:这个设置是配合batch.size
一起来设置,可避免消息长时间凑不满单位的Batch,导致消息一直积压在内存里发送不出去的情况。默认大小是0ms(就是有消息就立即发送)。上面两个参数条件,只要满足一个就会发送消息。