文章目录
1、什么是Kafka?
Kafka 是一个
分布式流处理平台
,最初由Linkedln开发并开源,后来成为Apache软件基金会的一个顶级项目。它被设计用于高吞吐量、持久性、分布式的数据流处理。
2、kafka基本概念
- Producer - 消息生产者,就是向kafka broker发消息的客户端
- Consumer - 消息消费者,是消息的使用方,负责消费Kafka服务器上的消息。
- Topic - 主题,由用户定义并配置在Kafka服务器,用于建立Producer和Consumer之间的订关系。生产者发送消息到指定的Topic下,消息者从这个Topic下消费消息。
- Partition - 消息分区,一个topic可以分为多个 partition,每个partition是一个有序的队列。partition中的每条消息都会被分配一个有序的id (offset)
- Broker - 一台kafka服务器就是一个broker。一个集群由多个broker组成。一个broker可以容纳多个topic。
- Consumer Group - 消费者分组,用于归组同类消费者。每个consumer属于一个特定的consumer group,多个消费者可以共同消息一个Topic下的消息,每个消费者消费其中的部分消息,这些消费者就组成了一个分组,拥有同一个分组名称,通常也被称为消费者集群。
- Offset - 消息在partition中的偏移量。每一条消息在partition都有唯一的偏移量,消息者可以指定偏移量来指定要消费的消息。
3、工作流程
- producer先从zookeeper的"/brokers/…/state"节点找到该partition的leader
- producer将消息发送给该leader
- leader将消息写入本地log
- followers从leader pull消息
- 写入本地log后向leader发送ACK
- leader收到所有SR中的replication的ACK后,增加HW (high watermark.最后commit 的offset)并向producer发送ACK
tips:Kafka 中消息是以topic 进行分类的,生产者生产消息,消费者消费消息,都是面向topic的。topic 是逻辑上的概念,而partition 是物理上的概念,每个partition 对应一个log 文件,该log 文件中存储的就是producer 生产的数据。Producer 生产的数据会被不断追加到该log 文件未端,且每条数据都有自己的offset。消费者组中的每个消费者,都会实时记录自己消费到了哪个offset,以便出错恢复时,从上次的位置继续消费。
4、Kafka的数据模型与消息存储机制
消息存储机制:
Kafka 有Topic 和 Partition 两个概念,一个 Topic 可以有多个 Partition。在实际存储的时候,Topic + Partition 对应一个文件夹,这个文件夹对应的是这个 Partition 的数据。在 Kafka 的数据文件目录下,一个 Partition 对应一个唯一的文件夹。如果有 4个 Topic,每个 Topic 有 5个Partition,那么一共会有 4*5 =20 个文件夹。而在 文件夹下,Kafka 消息是采用 Segment File 的存储方式进行存储的。
Segment File 的大概意思是: 将大文件拆分成小文件来存储,这样一个大文件就变成了一段一段 (Segment 段)。这样的好处是 10 加载速度快,不会有很长的10 加载时间。Kafka 的消息存储就采用了这种方式。
如上图所示,在一个文件夹下的数据会根据 Kafka 的配置拆分成多个小文件。拆分规则可以根据文件大小拆分,也可以根据消息条数拆分,这个是 Kafka 的一个配置,这里不细说。
在 Kafka 的数据文件夹下,分为两种类型的文件:
索引文件
(index File)和
数据文件
(Data File) 。索引文件存的是消息的索引信息,帮助快速定位到某条消息。数据文件存储的是具体的消息内容。
1)索引文件
索引文件的命名
统一为数字格式,其名称表示 Kafka 消息的偏移量
索引文件存储
的是简单地索引数据,其格式为: [N,Position]。其中 N 表示索引文件里的第几条消息,而 Position则表示该条消息在数据文件(Log File) 中的物理偏移地址。例如下图中的13.497,表示:索引文件里的第 3 条消息(即 offset 368772 的消息,368772 =368769+3),其在数据文件中的物理偏移地址为 497。
2)数据文件
数据文件就是所有消息的一个列表,而每条消息都有一个固定的格式,如下图所示。
从上图可以看到 Kafka 消息的物理结构,其包含了 Kafka 消息的 ofset 信息、Kafka 消息的大小信息、版本号等等。有了这些信息之后,我们就可以正确地读取到 Kafka 消息的实际内容。
5、ACKS 机制
在 Kafka 中,消息的 ACK (Acknowledgment,确认)机制与生产者的 acks 配置有关。acks 配置表示生产者在接收到消息后等待副本同步确认的方式,具体取值有:
- acks=0: 意义: 生产者在成功将消息发送给 Kafka 服务端后
不等待任何确认
。 结果: 生产者无法知道消息是否成功到达 Kafka 服务器,可能会导致消息的丢失。这种配置下,生产者不会收0到任何 ACK。 - acks=1: 意义: 生产者在成功将消息发送给 Kafka 服务端后,
等待该分区的首领节点 (leader)确认
。 结果: 生产者会收到分区首领节点的 ACK。这意味着只要分区首领节点成功接收到消息,生产者就会得到确o认,而不需要等待其他副本。 - acks=all 或 acks=-1: 意义: 生产者在成功将消息发送给 Kafka 服务端后,等待
所有分区副本确认
。 结果:生产者会等待分区的所有副本都成功接收到消息并确认。这是最安全的配置,因为只有当所有副本都确o认接收到消息后,才认为消息被成功提交。
6、生产者重试机制:
Kafka 生产者在发送消息后,如果设置了等待服务器的确认(通过 acks 参数配置),会等待一定时间来收到来自服务器的确认 (ack)。这个等待时间由 timeout.ms 参数控制,默认是 10000 毫秒 (10秒),如果在等待时间内没有收到服务器的确认,生产者可以选择重试发送或者处理发送失败的逻辑。这取决于生产者的配置。通常,生产者会根据
配置的重试次数
和
重试间隔
来进行重试,以确保消息最终被成功发送。
在 Kafka 的生产者配置中,你可以找到以下与重试相关的配置项:
- retries: 定义了生产者在发送消息时的最大重试次数.
- retry.backoff.ms: 定义了两次重试之间的等待时间间隔。
7、kafka是pull还是push
在 Kafka 中,消费者以 pull 模式工作。
- 优势:消费者通过定期向 Kafka Broker 发送请求来拉取消息。消费者可以根据自己的处理能力和需求来控制拉取的频率和每次拉取的消息量。可以批量拉取也可以单条拉取。
- 缺点:如果Kafka没有数据,会导致consumer空循环,消耗资源,可以通过参数设置,consumer拉取为空或者没有达到一定数量时阻塞(释放cpu)。
8、kafka高性能高吞吐的原因
1)磁盘顺序读写:保证了消息的堆积
- 磁盘顺序读写: Kafka 消息以日志的形式顺序写入磁盘,利用现代操作系统的
页面缓存
和顺序磁盘写入的高效性,极大地提高了写入性能。磁盘预读,预读即在读取的起始地址连续读取多个页面。 - 分区(Partitioning): 主题被划分为多个分区,每个分区在物理上是一个单独的日志文件,允许并行写入和读取。这种设计可以将负载分摊到多个服务器上,提高整体吞吐量。
Kafka 消息不是放在内存,也不依赖堆内存,而是放在页面缓存
2)零拷贝机制
Kafka 利用操作系统的
零拷贝机制
来减少 CPU 资源的消耗。通过直接将数据从
文件系统缓存
发送到
网络缓冲区
,避免了从用户空间到内核空间的多次数据拷贝,从而提高了数据传输效率。
LINUX操作系统本身实现了零拷贝技术,Kafka利用了这个优势
传统的数据复制:为了安全等问题,用户线程不能直接操作磁盘网卡等,需要由切换成内核态,由内核线程去操作,步骤如下:
- 读取磁盘文件数据到内核缓冲区
- 将内核缓冲区的数据copy到用户缓冲区
- 将用户缓冲区的数据copy到socket的发送缓冲区
- 将socket的发送缓冲区中的数据发送到网卡、进行传输 而零拷贝技术只用将磁盘文件的数据复制到页面缓存中一次,然后将数据从页面缓存直接发送到网络中:
3)分区分段+索引
- 分段日志: 每个分区的日志文件被分成多个段(segment),并且每个段都有自己的索引文件。这种设计不仅有助于快速查找消息,还可以方便地管理日志文件的大小和过期策略。
- 批处理(Batching): 消息在写入时被批处理,通过将多条消息放在同一个请求中,减少了网络往返次数,提高了网络利用率和吞吐量。
4)批量压缩
- 高效的数据压缩:Kafka 支持多种压缩格式(如 gzip、snappy、lz4 和 zstd),生产者可以在发送消息之前对数据进行压缩。压缩不仅减少了存储空间,还减少了网络带宽的消耗,提高了整体吞吐量。
- 异步写入: 生产者可以以异步方式将消息发送到 Kafka,这样生产者无需等待消息被完全写入,立即返回并继续处理其他任务。
- 批量发送: 生产者可以批量发送消息,合并多个消息到一个请求中,减少网络交互次数,提升发送效率。
5)直接操作pagecache
直接操作pagecache,而不是JVM,避免GC耗时和创建对象耗时,且读写速度更高,进程重启,数据也不会丢失
9、kafka的rebalance是什么
Kafka 的 Rebalance(重新平衡)机制是消费者组动态调整分区分配的重要机制。它确保消费者组成员数量变化(加入或离开)或分区数量变化时,分区能被重新合理地分配到消费者上,以维持负载均衡。
1) Rebalance 的触发条件
Rebalance 机制会在以下情况下被触发:
- 消费者加入消费者组:新的消费者加入消费者组时,需要重新分配分区。
- 消费者离开消费者组:现有消费者离开(故障或主动关闭)时,必须重新分配分区给其他消费者。
- 订阅主题的分区数量变化:如果一个主题增加或减少分区,也需要触发重新平衡。
- 消费者心跳超时:消费者没有在规定时间内发送心跳(heartbeat),会被认为已离开消费者组,触发重新平衡。
2)Rebalance 过程
- 消费者协调者(Consumer Coordinator): Kafka Broker 中有一个特定的组件称为消费者协调者,负责管理消费者组的成员和分配分区。
- 消费者加入组(Join Group): 每个消费者在启动时会向协调者发送 JoinGroup 请求,表明自己要加入某个消费者组。 协调者收到所有消费者的 JoinGroup 请求后,选举一个消费者作为组领导(Group Leader)。
- 组领导分配分区: 组领导根据分区分配策略(如 Range, RoundRobin, Sticky 等)生成新的分区分配方案,并将该方案提交给协调者。 协调者将分配方案发送给所有消费者。
- 消费者同步(Sync Group): 消费者收到新的分配方案后,会发送 SyncGroup 请求给协调者,表明自己已准备好接收新的分区。 当所有消费者都发送 SyncGroup 请求后,协调者完成重新平衡。
3)分区分配策略
Kafka 提供了几种分区分配策略:
- RangeAssignor: 默认分配策略。按分区顺序平均分配给消费者。适合主题数较少、每个主题分区数多的情况。
- RoundRobinAssignor: 按轮询方式分配分区。适合主题数较多、每个主题分区数较少的情况。
- StickyAssignor: 尽量保持之前的分配结果,仅在需要时才重新分配分区,以减少分区重新分配的次数,减少消费者重平衡的开销。
4)Rebalance 的影响
Rebalance 是一个昂贵的操作,会导致以下影响:
- 消息消费中断:在重新平衡过程中,所有消费者会停止消费,直到重新分配完成。
- 负载增加:重新平衡会导致分区的重新分配和消息的重新拉取,增加系统负载。
- 潜在数据重复消费:由于消费者可能在重新平衡前后重复拉取同一分区的消息,可能会导致数据重复消费。
5)Rebalance 的优化
为了减少 Rebalance 带来的影响,可以采取以下措施:
- 调整 session.timeout.ms 和 heartbeat.interval.ms 参数,确保消费者故障能快速被检测到,但也要避免频繁的心跳超时触发重新平衡。
- 消费者预分配策略: 使用 StickyAssignor 分配策略减少分区重新分配的频率和范围。
- 尽量减少消费者组的变动: 避免频繁启动或停止消费者,保持消费者组的稳定性。
10、kafka能保证消息的顺序消费吗
Kafka 提供了分区内顺序保证,但不保证全局顺序。
1)分区内顺序保证
分区内消息顺序:Kafka 保证同一分区内的消息是按发送顺序存储的。因此,对于同一分区内的消息,消费者会按照它们被生产者发送的顺序来消费。
2)保证消息顺序的策略
如果需要保证某些消息的顺序性,可以采用以下策略:
- 将所有消息放入一个分区: 通过使用单个分区,可以保证消息的全局顺序性。然而,这样做会限制并行处理能力和吞吐量,因为单个分区只能由一个消费者线程处理。
- 使用相同的键: 对于需要顺序处理的消息,使用相同的键将这些消息发送到同一个分区。这种方式可以在多分区的情况下部分保证顺序性。
3)应用层排序:
如果消息需要全局顺序,消费者可以在应用层进行排序。
例如,消费者在接收到消息后,可以根据消息的时间戳或其他顺序字段进行排序处理。
11、kafka消息如何保证不被重复消费
Kafka 提供了多种机制和策略来减少消息重复消费的可能性,包括
手动提交偏移量
、
幂等性生产者
、
事务性生产者
,以及在
应用层实现幂等性
。通过合理配置和使用这些机制,可以在很大程度上避免消息的重复消费,并确保消息处理的准确性和可靠性。
1)手动提交(enable.auto.commit=false)允许消费者在处理完消息后手动提交偏移量。
2)Kafka 生产者从 0.11.0.0 版本开始支持幂等性。启用幂等性后,Kafka 保证相同的消息不会被多次写入,即使由于网络分区或生产者重试。
配置幂等性生产者:
设置 enable.idempotence=true
3)Kafka 还支持事务性生产者,允许将多个消息发送到多个分区作为单个原子操作,以实现端到端的消息传递保证。
配置事务性生产者:
设置 transactional.id 和 enable.idempotence=true
4)消费者幂等性
虽然 Kafka 本身并不保证消费者的幂等性,但消费者可以通过在应用层实现幂等性来避免重复处理消息。常见的策略包括:
- 使用唯一标识符:每个消息携带唯一标识符,处理消息时检查是否已处理过该标识符。
- 数据库去重:在数据库中保存已处理消息的偏移量或唯一标识符,确保同一个消息不会被处理多次。
12、kafka如何保证消息不丢失
Kafka 通过在生产者、Broker 和消费者端的多层机制来确保消息不丢失。合理配置和使用这些机制可以在极大程度上保证消息的可靠性和系统的稳定性。以下是一些重要的配置总结:
生产者:acks=all、enable.idempotence=true、retries 和事务性生产者。
Broker:多副本、min.insync.replicas、日志持久化和保留策略。
消费者:手动提交偏移量、再平衡监听器和事务性消费者。
1)生产者端保证
- a. 设置 acks 参数 acks=all:确保消息被所有同步副本确认后才返回成功。这个配置保证了即使一个副本失败,消息也不会丢失。
- b. 重试机制 retries:设置重试次数,当发送消息失败时自动重试,避免临时的网络问题或其他临时故障导致消息丢失。
- c. 幂等性生产者 enable.idempotence:开启幂等性,确保即使重试,消息也不会被重复写入。
2)Broker端保证
- a. 副本机制 多副本:Kafka 的每个分区都有一个主副本和多个备份副本,确保数据冗余。 最小同步副本(min.insync.replicas):确保至少有 min.insync.replicas 副本是同步的,消息才能被写入。
- b. 数据持久化 日志文件持久化:Kafka 将消息持久化到磁盘,配置 log.dirs 设置日志存储目录,确保数据写入磁盘。
- c. 数据清理策略 日志保留策略:配置 retention.ms 和 retention.bytes 保证数据不会被过早清理,log.retention.ms 控制日志保留时间。
3)消费者端保证
- a. 手动提交偏移量 手动提交:消费者处理完消息后手动提交偏移量,确保在成功处理消息后才更新偏移量,防止消息处理失败导致的消息丢失。
- b. 再平衡监听器 再平衡监听器:实现 ConsumerRebalanceListener 接口,在分区再平衡前后提交偏移量,确保不会丢失消息。
4)事务保证
事务性生产者:确保多个消息和分区的原子写入,避免部分消息成功写入导致的数据不一致。
13、简述kafka副本同步机制
ISR详情参考:Kafka之ISR机制的理解
版权归原作者 一只IT攻城狮 所有, 如有侵权,请联系我们删除。