为什么这么快
上篇 文章提到了kafka的结构,其中有3点有助于提高它的吞吐量。
- partition并行处理
多个partition承载一个topic的消息存储和传输,增加partition的数量能有效增加吞吐量。 - 写消息:消息存储采用顺序写的方式
kafka消息存储在log文件中,文件采用顺序写的方式写入消息。由于磁盘结构,顺序写要比随机写快不少。
补充:
写消息还有一点优化,生产者向broker发送消息过程会先向Page Cache里写入,再异步刷盘到log文件。
为防止消息丢失,可以采用replication备份的方式。
- 读消息:文件命名和稀疏索引
两者保证了消息的快速定位,加速消息消费。
- 零拷贝技术
文章图片
应用程序发起读数据请求,磁盘数据经read buffer进入应用层buffer;再由应用层buffer进入socket buffer,通过网卡进行网络传输。
一份数据未做任何改变的前提下,经历了数次拷贝,期间还涉及用户态和内核态间的转换,这显然是一种浪费。
文章图片
kafka利用DMA技术,实现了零拷贝。
DMA可以用在显卡、声卡等很多硬件上,这里主要用到了网卡的DMA通过操作系统层面的sendfile函数,数据将简历read buffer到网卡的映射,然后直接发送出去。(要保证数据未做任何改变)
而java的transferTo方法底层基于操作系统的sendfile实现。
升级后的方式不再需要用户态和内核态之间的切换,同时也免去了多次拷贝。
- 其它
当然,kafka支持的批量消息和消息压缩都是其快的原因。
先看下如下几个概念:
- AR(Assigned Repllicas)一个partition的所有副本(就是replica,不区分leader或follower)
- ISR(In-Sync Replicas)能够和 leader 保持同步的 follower + leader本身 组成的集合。
- OSR(Out-Sync Relipcas)不能和 leader 保持同步的 follower 集合
- 公式:AR = ISR + OSR
有关同步的配置如下:
# 默认10000 即 10秒
replica.lag.time.max.ms
这个配置的意思是10秒内达成完全同步的副本,会记录在ISR集合中;未完全同步则移出集合。
好,我们来看看完全同步的意思。在这之前先引出两个概念:
文章图片
- LEO(last end offset)
一个partition中,最新消息的下一个offset - HW(high watermark)
partition的所有replication中同步的最小offset。
图中的例子:当replication将partition的LEO之前的日志全部同步时,则认为该replication已经追赶上partion,也就是完全同步。
假如partition有8条消息(0-7),LEO为8;
这个partition有3个replication,其中的两个partition已经将8条消息同步了;
最后一个replication只同步了5条消息(0-4),那么HW会标记为5。
此时消息0-4对外可见(consumer可以消费),5-7不可见。
同时,10秒内此replication不能将5-7消息同步,它将被移出ISR
附录 【kafka(下)(快、主从同步)】P6-P7知识合辑