(三)kafka高吞吐王牌杀手锏
A. 顺序读写
-
影响因素
- 机械硬盘的io有两个阶段,分别为寻址 & 写入。
- 寻址:物理动作,通过旋转和磁臂找到对应扇区,其动作较慢,耗时是毫秒级。
- 写入:数据的写入阶段很快,非优化重点方向。
核心效果:producer倾倒消息时是不断追加到文件的形式,因此kafka利用追加写入完成磁盘顺序读写,减少磁盘磁头寻道时间,远快于随机读写。
-
补充说明:linux io调度有4种方法
- NOOP(先进先出的队列)
- CFQ(默认方法,根据io请求的地址排序,但是这导致小的io动作如果地址靠后的话就需要一直等待)
- DEADLINE(CFQ的升级版,设置了等待时间的上限)
- ANTICIPATORY(每个io请求都等6ms,如果这个时间内收到了地址相近的操作就合并一起)
B. 零拷贝zero copy
核心效果:基于linux的send file命令,减少内核态到用户态之间的拷贝。
-
具体流程
- 在内核态kernel中操作,将数据从disk复制到memory buffer,在kafka的场景下,其实数据从disk走到了page cache;
- 从page cache中把数据传递到socket buffer,最后给到nic buffer发出去。
优势:上述两步操作都在内核态kernel中完成,若没有send file机制数据需要从第一步的page cache拷贝到用户态的kafka应用中,然后再从kafka应用中拷贝到内核态的socket buffer中,多了两次拷贝动作。
C. 页缓存page cache
- 核心效果:数据在内存memory中的读写速度高于在磁盘disk下的读写速度,而page cache就是利用内存空间来实现提速的。
- 具体流程:结合上方的zero copy,kafka完成了数据传输的“空中接力”。
- 生产者将数据发送到broker;
- broker将数据先存至page cache,再刷入磁盘;
- 消费者此时若拉取数据,数据可基于send file,在broker上直接从page cache中到socket buffer,再从nic buffer送出;
- 消费者凭借zero copy,结合page cache的加速更快获得数据。
- 注意点:kafka会用到大量memory作为page cache,所以linux的swap空间会被使用起来,一些不活跃的进程被放入了swap。
D. 分区机制partition
1. 分区过多会破坏Kafka追加写
- partition底层对应的是一个或多个segment文件,若分区过多会导致有大量segment文件。虽然每个文件单独看都是追加写的模式,但是系统宏观角度下会切换写入多个segment文件,这样寻址成本等于是随机io(rocketMQ对此作了优化,所有分区数据写入一个commitLog)。
- 若kafka部署在云盘或者使用ssd就不用担心该问题,前者走带宽,后者不需要物理寻址。
2. Kafka数据存储结构
Topic & partition:Topic由大量partitions构成,利用分布式结构分散在不同broker节点上增加并行能力,而提升partition可以进一步利用并发能力,随着增加对应下有消费者数目,尽可能地提升吞吐量。
-
存储的微观单位:每个partition有单独的目录,目录下又被具体分为多个segments,单个segment由一对文件——索引文件 & 数据文件。默认情况下segment的数据文件大小为
log.segment.bytes=1073741824
,即1gb。-
索引文件:0000000.index,其名称为该段的起始索引号,总体采用是稀疏索引的方式。索引文件由message索引号(从1开始)和该message的末尾offset组成。
Message index Message position annotation 1 0 第一条空的 3 4597 稀疏index,直接index=3 6 9807 -
数据文件:0000000.log,保存上方索引文件对应的数据内容,由数据和position组成。
message data Message position annotation Message1 data part 0 第一条空的 Message2 data part 2039 数据文件不可能稀疏,完整记载末尾的offset是多少 Message3 data part 4597 对应index=3的情况 Message4 data part 6830 Message5 data part 7912 Message6 data part 9807 对应index=6的情况
-
-
删除机制
- 周期检查:broker server周期性地检测和删除不符合保留条件的segments,具体周期根据配置的
log.retention.check.interval.ms
参数,默认为5分钟。 - 基于时间保留:基于配置的
log.retention.ms | log.retention.minutes | log.retention.hours
(若都配置了,优先级罗列的这个顺序逐级降低),默认168hours(7天)。非激活状态下的segment超过这个时长后,会被清理。 - 基于文件大小保留:基于
log.retention.bytes
的配置,目录下所有segments的数据文件大小若大于这个值,则删除最早的segment。
- 周期检查:broker server周期性地检测和删除不符合保留条件的segments,具体周期根据配置的
E. 其他手段
- 批量发送:生产者客户端缓存消息后批量发送给broker,消费者也批量从broker拉取数据,减少网络上的io次数。
- 网络瓶颈:kafka的核心性能瓶颈不是cpu、磁盘,而是网络带宽,需尽可能的压缩数据(下个主题对kafka的网络进行了阐述说明)。