基础架构
架构图
安装目录
高性能原因
- 分布式集群
Kafka 本身是分布式集群,可以采用分区技术,并行度高;
- 稀疏索引
读数据采用稀疏索引,可以快速定位要消费的数据;
- 顺序写磁盘
Kafka 的 producer 生产数据,要写入到 log 文件中,写的过程是一直追加到文件末端,为顺序写。官网有数据表明,同样的磁盘,顺序写能到 600M/s,而随机写只有 100K/s。这与磁盘的机械机构有关,顺序写之所以快,是因为其省去了大量磁头寻址的时间。
- 零拷贝
Kafka Broker应用层不关心存储的数据,所以就不用走应用层,传输效率高。 Kafka的数据加工处理操作交由Kafka生产者和Kafka消费者处理。
- PageCache页缓存
Kafka重度依赖底层操作系统提供的PageCache功 能。当上层有写操作时,操作系统只是将数据写入PageCache。当读操作发生时,先从PageCache中查找,如果找不到,再去磁盘中读取。实际上PageCache是把尽可能多的空闲内存都当做了磁盘缓存来使用。
原理过程
数据存储
ZK存储节点信息
文件存储机制
Topic是逻辑上的概念,而partition是物理上的概念,每个partition对应于一个log文件,该log文件中存储的就是Producer生产的数据。Producer生产的数据会被不断追加到该log文件末端(顺序写),为防止log文件过大导致数据定位效率低下,Kafka采取了分片和索引机制,将每个partition分为多个segment。每个segment包括:".index"文件、".log"文件和.timeindex等文件。这些文件位于一个文件夹下,该文件夹的命名规则为:topic名称+分区序号,例如:first-0。
文件存储机制-index文件和log文件
文件清理机制
Kafka 中默认的日志保存时间为 7 天,可以通过调整如下参数修改保存时间: log.retention.hours: 最低优先级小时,默认 7 天; log.retention.minutes: 分钟;log.retention.ms,最高优先级毫秒;log.retention.check.interval.ms: 负责设置检查周期,默认 5 分钟; 如果日志一旦超过了设置的时间,kafka提供了俩种日志清理机制:
log.cleanup.policy = delete 所有数据启用删除策略; compact日志压缩:对于相同key的不同value值,只保留最后一个版本;
log.cleanup.policy = delete 所有数据启用删除策略 delete 日志删除:将过期数据删除 a. 基于时间:默认打开。以 segment 中所有记录中的最大时间戳作为该文件时间戳。 b. 基于大小:默认关闭。超过设置的所有日志总大小,删除最早的 segment。 log.retention.bytes,默认等于-1,表示无穷大。 c. 思考:如果一个 segment 中有一部分数据过期,一部分没有过期,怎么处理?等待获取最新数据时间戳,也就是所有记录中的最大时间戳,作为判断过期的依据,然后进行清理。
log.cleanup.policy = compact 所有数据启用压缩策略 compact日志压缩:对于相同key的不同value值,只保留最后一个版本。
a. 压缩后的offset可能是不连续的,比如上图中没有6,当从这些offset消费消息时,将会拿到比这个offset大 的offset对应的消息,实际上会拿到offset为7的消息,并从这个位置开始消费。
b. 这种策略只适合特殊场景,比如消息的key是用户ID,value是用户的资料,通过这种压缩策略,整个消息集里就保存了所有用户最新的资料。
运行流程
生产者发送消息流程
在消息发送的过程中,涉及到了两个线程------main 线程和 Sender 线程。 在 main 线程中创建了一个双端队列 RecordAccumulator。main 线程将消息发送给 RecordAccumulator,Sender 线程不断从 RecordAccumulator 中拉取消息发送到 Kafka Broker。
指定分区
kafka分区的好处:a. 便于合理使用存储资源,每个Partition在一个Broker上存储,可以把海量的数据按照分区切割成一块一块数据存储在多台Broker上。合理控制分区的任务,可以实现负载均衡的效果。
b. 提高并行度,生产者可以以分区为单位发送数据;消费者可以以分区为单位进行消费数据。
kafka分区设置: a. 指定分区; b. key的hash值和分区数取模; c. 粘性分区器随机选择; d. 自定义分区器;
消息确认ACK机制
Broker工作流程
启动
选举
Kafka 集群中有一个 broker 的 Controller 会被选举为 Controller Leader,负责管理集群broker 的上下线,所有 topic 的分区副本分配和 Leader 选举等工作。
Controller 的信息同步工作是依赖于 Zookeeper 的。
副本数据同步-Leader和Follower故障
Broker的分区副本分配
Kafka分区的好处:a. 便于合理使用存储资源,每个Partition在一个Broker上存储,可以把海量的数据按照分区切割成一块一块数据存储在多台Broker上。合理控制分区的任务,可以实现负载均衡的效果;
b. 提高并行度,生产者可以以分区为单位发送数据;消费者可以以分区为单位进行消费数据; Kafka分区的副本分配方式:如果 kafka 服务器只有 4 个节点,那么设置 kafka 的分区数大于服务器台数,在 kafka底层如何分配存储副本呢? 创建 16 分区,3 个副本: bin/kafka-topics.sh --bootstrap-server hadoop102:9092 --create --partitions 16 --replication-factor 3 --topic second,分区如下:
Broker的Leader Partition重平衡
kafka中会有多台broker, 多个topic, 每个topic都会有多个分区,一个leader副本。那这多个topic的leader副本具体分布到哪些broker上,以及当broker宕机时,这些topic的leader副本又会怎么分配?
消费者组消费流程
消费者组
Consumer Group(CG):消费者组,由多个consumer组成。形成一个消费者组的条件,是所有消费者的groupid相同。
a. 消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一个组内消费者消费;
b. 消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者;
c. 如果向消费组中添加更多的消费者,超过主题分区数量,则有一部分消费者就会闲置,不会接收任何消息;
d. 消费者组之间互不影响。所有的消费者都属于某个消费者 组,即消费者组是逻辑上的一个订阅者;
消费模式
消费者组初始化流程
消费者组消费流程
消费者组分区分配策略和重平衡-Range
一个consumer group中有多个consumer组成,一个 topic有多个partition组成,现在的问题是:到底由哪个consumer来消费哪个partition的数据,还有消费者重启期间和重启后的消费方案; Kafka有四种主流的分区分配策略: Range、RoundRobin、Sticky、CooperativeSticky;
可以通过配置参数partition.assignment.strategy,修改分区的分配策略。默认策略是Range + CooperativeSticky。Kafka可以同时使用多个分区分配策略;
消费者组分区分配策略和重平衡-RoundRobin
一个consumer group中有多个consumer组成,一个 topic有多个partition组成,现在的问题是:到底由哪个consumer来消费哪个partition的数据,还有消费者重启期间和重启后的消费方案; Kafka有四种主流的分区分配策略: Range、RoundRobin、Sticky、CooperativeSticky;
可以通过配置参数partition.assignment.strategy,修改分区的分配策略。默认策略是Range + CooperativeSticky。Kafka可以同时使用多个分区分配策略;
消费者组分区分配策略和重平衡-粘性
一个consumer group中有多个consumer组成,一个 topic有多个partition组成,现在的问题是:到底由哪个consumer来消费哪个partition的数据,还有消费者重启期间和重启后的消费方案; Kafka有四种主流的分区分配策略: Range、RoundRobin、Sticky、CooperativeSticky;
可以通过配置参数partition.assignment.strategy,修改分区的分配策略。默认策略是Range + CooperativeSticky。Kafka可以同时使用多个分区分配策略;
offset相关-Consumer_offsets主题
__consumer_offsets 主题里面采用 key 和 value 的方式存储数据。key 是 group.id+topic+分区号,value 就是当前 offset 的值;
每隔一段时间,kafka 内部会对这个 topic 进行compact,也就是每个 group.id+topic+分区号就保留最新数据;
__consumer_offsets 为 Kafka 中的 topic,那就可以通过消费者进行消费,在配置文件 config/consumer.properties 中添加配置 exclude.internal.topics=false,默认是 true,表示不能消费系统主题;
offset相关-自动提交与手动提交
Kafka提供了自动提交和手动提交offset的功能;自动提交是基于时间提交的,手动提交更加灵活可控。
手动提交offset的方法有两种:分别是commitSync(同步提交)和commitAsync(异步提交)。
两者的相同点是,都会将本次提交的一批数据最高的偏移量提交;
不同点是,同步提交阻塞当前线程,一直到提交成功,并且会自动失败重试(由不可控因素导致,也会出现提交失败);而异步提交则没有失败重试机制,故有可能提交失败。
• commitSync(同步提交): 必须等待offset提交完毕,再去消费下一批数据,会阻塞当前线程,影响吞吐量,不常用;
• commitAsync(异步提交) :发送完提交offset请求后,就开始消费下一批数据了,比较常用;
offset相关-重复消费与漏消费
Kafka提供了自动提交和手动提交offset的功能,存在重复消费和漏消费的问题;
实战经验
幂等性
事务
数据有序
kafka只能保证单分区有序,多分区无法保证;