一.前言
学习以及使用kafka有一段时间了,有必要对kafka做一些笔记,本片文章重点记录kafka底层的设计,对于一些参数以及client的demo等读者可以自行查看官网
二. kafka底层设计
我们知道kafka各项指标(吞吐量,延迟性以及持久化等指标)很优,而kafka毕竟是需要将日志持久化到磁盘中的,那么kafka是如何做到的呢?
1.顺序写入
kafka持久化日志是采用append方式写入的,即顺序写入磁盘的。磁盘的顺序读写操作是很快的,毕竟减少了最最重要的找到磁盘寻址的开销,甚至可以匹敌内存的随机I/O速度。实际上涉及到需要存储并落盘大量数据的系统基本都是顺序写入的e.g. hbase 等
2.操作系统的page cache
默认情况下(即可以通过参数属性log.flush.interval.ms等改变默认值),kafkaProducer 虽然会将数据持久化到磁盘,但本质上每次写入操作其实是将数据写入到操作系统中的page cache(页缓存)中(这里的页缓存可不是producer 中的buffer.memory哦),数据的真正落盘是交给操作系统自行决定来完成。 疑问:可能会问,page cache到底还内层中,如果所在的broker宕机了那数据岂不是会丢?这个问题是存在的,不过如果配置了ack=all,并且in.insync.replicas>1,总不至于所有的insync.replicas所在的节点都宕机吧,这样的故障是极小概率的!
数据先保存到page cache中不仅仅提高到producer端的写入性能,还提高了consumer的读性能。默认情况consumer会先page page中读取。kafka设计的初衷就是kafka producer写入到page cache,然后consumer 从page cache 中读取数据。 这样可以完全避免走磁盘的过程,所有的过程都是在内存中完成 ,这样岂不是快哉。 落盘看上去仅仅是一个后台“异步”写到磁盘的过程。
3. 数据传输之 zero copy
居然kafka消息引擎,自然免不了消息的传输,随着操作系统的不断完善,早已经出现zero copy的技术从字面意思就是不需要来回copy 。当我们需要传输数据时,生产数据流程大致分为 网卡缓存-> socket缓存->应用程序缓存 -> 操作系统内核缓存-> 磁盘 等,在这些过程中需要copy的。能不能减少copy次数就是需要解决的问题,kafka 操作系统DMA等方式来实现 跳过 应用程序缓存相关环节的拷贝(关于zero copy相关链接 参考:https://maimai.cn/article/detail?fid=1236304197&efid=u4GUhDloTNP1da_BcFd-4Q)
4. 采用batch 方式来读写数据
小的batch 虽然一定程度上影响了延时性(不过延时性在可以接受的范围内),但换取的可能是百倍的吞吐量。
5.其他
紧凑的传输协议(bytebuffer)等