Kafka作为AMQP实现中一个比较特殊的存在,网上的说法都是极高的吞吐。不同于一般MQ的设计方式,kafka充分的利用了操作系统特性,并经过特殊的设计即在保证极高的吞吐量同时也尽可能的保证消息的一致性。
分区&副本(partition&replication)
分区
- 分区(partition)是卡夫卡保证高吞吐的基本保证,一个topic通常会有多个partition,可以分别部署在一台或多台主机上。
- 每个partition只能对应一个consumer,而一个consumer可以对应多个partition(多出的consumer会闲置)
- 每个partition可以有多个replicas,且必须部署在不同的主机上(部署在同一主机上是没有意义的)。
副本
- replicas只负责备份数据,并不能用于读写
- replicas通过poll的方式从partition获取数据。
为什么要使用poll而不是用push?因为拉可以减少leader的消耗,并且可以批量获取数据。
- 当partition失效时,某个replica晋升为leader才能继续提供读写。
日志形式消息文件存储
kafka的日志文件形式是其区别于其他MQ的最关键因素,也是其保证吞吐量的核心
写日志
分段日志
kafka的日志文件是分段的,每个分段文件包含一个索引文件(index),一个日志文件(log),一个时间戳索引文件(timestamp);以该段的第一条消息的偏移量(offset)作为文件名存储消息日志,文件名长度为20位,不足的补0。
- 日志文件是怎么分割的?
- 1,按照配置的日志文件大小分割,默认1G
- 2,按照日志对应的索引文件大小分割,默认索引文件大小10mb
- 3,按时间分割,默认分割时间7天,即7天后会写入新文件
-
4,按消息数量分割,当消息数量超过Integer.MAX_VALUE后会写入新文件
image.png
顺写日志
零拷贝
索引文件
- 每个索引条目占8个字节,前4字节表示消息偏移量,后4字节表示物理位置(这也可以解释为什么上面写的消息数量不能超过Integer.MAX_VALUE)
- 注意,不是每条消息都会在索引里,而是每隔一定量的字节后写一条索引(log.index.interval.bytes)。
读日志
https://segmentfault.com/a/1190000019147699
- 索引的每个条目包含了一条消息的序号(offset)和消息在文件中位置(position)
- 注意,不是每条消息都会在索引里,而是每隔一段字节保存(这个字节数不是很清楚)。
- 如何读取offset=7的消息?
- 首先根据偏移量就能找到对应的日志文件
- 根据日志索引再使用二分查找法找到之前最近的一条日志索引offset=6
- 再根据offset=6的position找到文件中位置,再遍历到offset=7的消息
生产者策略
批量拉取数据
以java client为例
image.png
producer会先将消息存储在一个队列里,然后由Sender轮询去批量拉取
消费者策略&低级api
批量拉取策略
由consumer自行决定拉取速率及数量,充分保护consumer
默认由kafkacluster保存topic.consumer_offset
低级api自定义offset
可由consumer控制的offset,保证Exactly once
ISR&HW&LEO
ISR副本原则
HW&LEO
。。。。未完待续
网友评论