深入理解Kafka

基础架构

架构图

安装目录

高性能原因

  • 分布式集群

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只能保证单分区有序,多分区无法保证;

提高吞吐量

核心参数

生产者端核心参数

Broker端核心参数

消费者端核心参数

相关推荐
技术路上的苦行僧2 小时前
分布式专题(8)之MongoDB存储原理&多文档事务详解
数据库·分布式·mongodb
龙哥·三年风水2 小时前
workman服务端开发模式-应用开发-后端api推送修改二
分布式·gateway·php
小小工匠3 小时前
分布式协同 - 分布式事务_2PC & 3PC解决方案
分布式·分布式事务·2pc·3pc
闯闯的日常分享5 小时前
分布式锁的原理分析
分布式
太阳伞下的阿呆6 小时前
kafka常用命令(持续更新)
分布式·kafka
Java程序之猿6 小时前
微服务分布式(二、注册中心Consul)
分布式·微服务·consul
龙哥·三年风水7 小时前
workman服务端开发模式-应用开发-后端api推送修改一
分布式·gateway·php
power-辰南8 小时前
Zookeeper 底层原理解析
分布式·zookeeper·云原生
power-辰南8 小时前
Zookeeper常见面试题解析
分布式·zookeeper·云原生
bug_null14 小时前
RabbitMQ消息可靠性保证机制7--可靠性分析-rabbitmq_tracing插件
分布式·rabbitmq