Kafka基本概念
Broker
Kafka集群的一个进程,在集群内由唯一id进行标识;当Broker接到消息,将其存储在磁盘,同时根据配置将消息复制到其他Broker,保证消息的可靠性;消费时根据请求,从磁盘读取相应的消息返回给消费者;
- 独立接收消息请求;
- 与其他Broker通讯协同;
Topic
Topic是一个逻辑概念,用于对消息进行分类管理,通常一个topic对应一类业务消息;简单来说:生产者将消息发送到特定的 Topic,消费者则从感兴趣的 Topic 中获取消息;
- 一个Topic对应多个partition;
Partition
Partition是Topic下的物理分区。一个 Topic 可以包含多个 Partition,每个 Partition 都是一个有序的、不可变的消息序列,消息在 Partition 中按照顺序被分配一个唯一的偏移量offset;
Partition核心目的:实现数据的分布式存储和并行消费;
Partition和消费者的关系:
- 同一个Partition只能被同一个消费者组的一个消费者消费;(否则出现重复消费,offset是以消费者组来记录的)
- 同一个消费者,可以消费同一个Topic下的多个Parition;(每个Partition的消息不会重复,可以正常消费多个Parition)
- 最佳配比:消费者数量 == partition分区数
Partition的高可用:
- 每个Partition可以根据配置存储多个副本;通常副本数量为Broker节点数 - 1,即:Broker节点数 = Leader + Follower
- Leader:负责所有的读写任务(生产消费任务);
- Follower:仅负责备份消息;当Leader故障,通过选举进行故障转移;(选举的过程设计ISR机制)
ISR(In - Sync Replicas,同步副本集):对于分区的Leader来说,可靠的副本集合;
- 可靠的副本:消息备份落后时间在一定范围内(replica.lag.time.max.ms)以及消息数量落后在一定范围内(replica.lag.max.messages),被认为是可靠的、可以用于故障转移和数据恢复的副本;
- 消息的确认机制、故障转移机制都只会考虑ISR,而不是全部的副本;
- ISR是动态维护的,副本可能被踢出ISR,也可以重新加入ISR;
Partition和消费者的分配策略:
- Range:按照分区的范围进行分配,将主题的分区按照一定的规则划分成多个范围,然后将每个范围分配给一个消费者;
- RoundRobin:将主题的分区依次轮流分配给消费者组中的各个消费者;
- Sticky:尽可能地将分区分配给相同的消费者,以减少分区的重新分配;
- 如果消费者数量大于分区数,则会存在空闲的消费者;
Partition和消费者数量关系:一个消费者,可以消费多个Partition;一个Partition只能被同组一个消费者消费,可以被不同组多个消费者消费; 同一个topic下的Partition数量(P)与同一个消费者组下的消费者数量(C)的关系:
- 当C < P,就存在某消费者消费多个Partition;
- 当C = P,效率最高,最大并行度;
- 当C > P,多余的消费者,不会消费这个Topic数据;
Offset
生产端offset:当生产者向 Kafka 主题的某个分区写入消息时,每条消息都会被分配一个唯一的 offset。这个 offset 是一个单调递增的整数,
消费端offset:offset消费进度是以消费者组为单位,每个消费者组在每个Partition中都有自己独立的offset,存储在kafka的内部主题
- 自动提交offset:消费者可以将enable.auto.commit参数设置为true,从而开启自动提交 offset 功能。在这种模式下,消费者会按照auto.commit.interval.ms参数指定的时间间隔,定期将当前消费到的 offset 提交到__consumer_offsets主题
- 手动提交offset:消费者也能将enable.auto.commit参数设置为false,然后手动提交 offset。手动提交能让消费者更精确地控制 offset 的提交时机,避免因自动提交导致的消息重复消费或丢失问题
offset重置策略:当消费者组首次消费某个主题,或者指定的 offset 不存在时,就需要采用 offset 重置策略;参数:
- earliest:从分区的起始位置开始消费消息。
- latest:从分区的最新位置开始消费消息。
Producer
通常指Kafka的生产客户端:负责将消息发送到Kafka服务端,投递到对应的Topic甚至Parition中(如果指定了Partition);
Consumer
消费者组:一组相关的消费者,它们共同消费一个或多个 Topic 中的消息;
消费者组的设计目的:在一个 Consumer Group 中,每个消费者负责消费 Topic 中不同 Partition 的消息,从而实现并行消费和负载均衡;
消费者:指kafka的消费客户端,根据订阅的topic从Kafka服务端的某个Partition按顺序拉取消息;
Kafka的存储
1. 存储结构
Kafka的Topic分多个Partition来提高并行度,每个Partition又由多个Segment构成,实现消息存储; 每个Segment段分为:
- .log文件:采用追加写的方式,追加到1G大小,生产一个新的Segment;
- .log文件:记录每一条消息的元数据,包括在此文件内的偏移地址,创建时间,消息存储的物理地址;
- .index文件(稀疏索引):log日志每追加4kb,在index中记录追加的消息起始偏移量、起始position;
- .index文件:用于通过offset进行索引消息;会以最小offset命名;
- .timeindex文件:用于通过时间戳进行索引消息;
2. 消息寻址
寻址主要通过下面几个参数:
- .index[消息偏移量,position指针],position指向.log的position
- .log[消息offset,position指针]
假设查找offset:177854消息寻址过程:(二分搜索)
- 搜索到17784在[17780-18253]之间,就锁定了以17780为起始的segment(.index文件)
- 根据.index记录,找到offset的偏移位置区间,17783在17780+3~6的偏移位置之间,因此锁定指针153
- 在.log文件中从153开始向下顺序查找,找到offset 17784消息
- 从磁盘读取并发送此条消息(零拷贝)
Kafka的副本机制
Kafka的高性能
1. Parition的并行消费
当消费者数量对应Partition数量,可以达到最大消费速率;
可以增加Partition数量,横向扩展并行度;
2. 生产消费批处理
批量发送 和 批量拉取极大提升吞吐量;
3. 零拷贝技术
减少数据拷贝次数,线程上下文切换次数;
- 索引文件:mmap + write;通常是消费端指定offset读取时用到;
- 消息文件:sendfile;通过索引,找到消息后,通过sendfile发送消息;
4. 顺序写/顺序读/磁盘预读
- 顺序写只需要数据写入时间,减少寻道、磁头旋转时间
- 大量利用page cache,写数据不需要真正写入磁盘;
- 读操作可以利用磁盘预读,连续读取多个页面,减少磁盘IO;
5. 高效存储:稀疏索引 + 二分搜索
二分搜索 + 稀疏索引 实现高效查询操作(通过时间戳和offset)
- 通过时间戳和offset 进行二分搜索;
- 稀疏索引:多条消息才会生成一个索引;
6. 消息压缩
消耗一定的CPU,提高网络传输效率,提高吞吐量;
- 生产端可用通过配置:compression.type = gzip对消息进行单个或批量压缩;减少数据大小;
- 生产端同样配置有压缩算法;当与生产端压缩算法相同,则不需要解压缩,并且能够用到零拷贝;
- 当压缩算法不一致,就需要对数据进行解压,再次压缩,势必需要将数据拷贝到用户空间进行处理;
- 当压缩算法一致,不需要对消息进行额外处理,
- 消费端直接拉取压缩的数据,在客户端进行解压缩;