Kafka
主题、分区、消息、消费者组、消费者
一个topic可设置多个分区,一条消息只会被存储到一个分区上,分区内消息顺序存储
- 分区是提升IO并发的手段
一个消费者组里的一个消费者只会消费一次一个分区上的一条消息
多个消费组可以消费多次消息
零拷贝
零拷贝不是没有拷贝,而是减少拷贝次数
传统IO流程
- 第一次:将磁盘文件,读取到操作系统内核缓冲区;
- 第二次:将内核缓冲区的数据,copy 到 application 应用程序的 buffer;
- 第三步:将 application 应用程序 buffer 中的数据,copy 到 socket 网络发送缓冲区(属于操作系统内核的缓冲区);
- 第四次:将 socket buffer 的数据,copy 到网卡,由网卡进行网络传输。
Memory Mapped Files(mmap)
kafka利用顺序存储优化磁盘寻址
直接利用操作系统的 Page 来实现文件到物理内存的直接映射,完成映射之后你对物理内存的操作会被同步到硬盘上(操作系统在适当的时候)
通过 mmap,进程像读写硬盘一样读写内存(当然是虚拟机内存),也不必关心内存的大小,有虚拟内存为我们兜底
优点
- 以操作内存的性能实现对硬盘文件的操作
缺点
- 不可靠,可能存在内存未同步到硬盘的场景
Kafka提供参数 producer.type 来控制是不是主动 Flush
- 如果 Kafka 写入到 mmap 之后就立即 Flush,然后再返回 Producer 叫同步 (Sync)。
- 如果 Kafka 写入 mmap 之后立即返回 Producer 不调用 Flush 叫异步 (Async)。
sendfile
运行流程如下:
- Sendfile 系统调用,文件数据被 Copy 至内核缓冲区。
- 再从内核缓冲区 Copy 至内核中 Socket 相关的缓冲区。
- 最后再 Socket 相关的缓冲区 Copy 到协议引擎。
减少了到进入和离开用户空间的两次拷贝
Leader重新选举
选举流程
第一步:选出选举委员会主席(Controller)
补充问题:
kafka是如何从Broker中选出唯一的Controller? 答: 选举时,所有的Broker会尝试在Zookeeper中创建临时节点/controller,谁先创建成功,谁就是Controller.
如果Controller挂掉了或是网络出现异常时,kafka将会如何处理? 答: 如果Controller挂掉了或是网络出现异常时,这个Controller临时节点就会消失,其它的Broker节点就会由于Watch机制,监听到Controller下线的通知,然后继续按照先到先得的原则,选举一个新的Controller节点; 第二步:定下候选人员
只有在ISR中,保持心跳同步的副本,才有资格参与竞选;
补充问题
什么是ISR? 答: 一个分区所有的副本,叫做Assigned-Replicas(AR) 。所有的皇太子。 这些所有的副本中,跟leader数据保持一定程度同步的,叫做In-Sync Replicas(ISR) 。 跟leader同步滞后过多的副本,叫做Out-Sync-Replicas(OSR) 。 AR=ISR+OSR。正常情况下OSR是空的,大家都正常同步,AR=ISR。 谁能够参加选举呢?肯定不是AR,也不是OSR,而是ISR。而且这个ISR不是固定不变的,还是一个动态的列表。 前面我们说过,如果同步延迟超过30秒,就踢出ISR,进入OSR; 如果赶上来了,就加入ISR。
第三步:Leader选举开始
默认是让ISR中的第一个副本变成Leader。即:如果ISR中的链表顺序为:1-5-9,那么节点1将会成为Leader;
分布式选举中,有很多选举协议:ZAB(zookeeper), Raft(redis)等等 (先到先得,少数服从多数原则)
消息存储
为了满足基本的生产、存储、消费需求的话,需要2个文件:
- xxxxxxxxx.log 例如:00000000000000000000.log
- xxxxxxxxx.index 例如:00000000000000000000.index
其中log文件是用来存储消息的,而index文件则是用来存储稀疏索引的
- log文件:通过append的方式向文件内进行追加,每个Segment对应一个log文件
- index文件:索引文件,每隔4K存储一次offset+position,帮助快速定位指定位点的文件position用的
Kafka应答机制
- acks=0(不等待确认)。这是最低延迟的选项,生产者发送消息后不会等待来自Broker的任何确认。它会立即继续发送下一条消息。这种模式下,生产者无法知道消息是否已经成功到达Broker,因此数据的丢失可能性比较大。
- acks=1(Leader确认)。在这种模式下,生产者发送消息后会等待Broker的领导者(Leader)确认。领导者会确认消息已经被接收,但不一定已经被完全复制到所有的副本。这种模式提供了一定程度的可靠性,因为生产者知道消息至少已经被领导者接收,但仍然可能丢失消息,因为它们可能还没有被复制到其他副本。
- acks=-1(全部确认)。这是最可靠的确认模式,在这种模式下,生产者发送消息后会等待所有的ISR(In-Sync Replicas,同步副本)确认。ISR是分区的所有副本中与领导者保持同步的副本集合。在这种模式下,消息只有在被领导者和所有同步副本都确认接收后才被视为已提交。这确保了消息的可靠性。但是,这种模式下,效率是最低的。
kafka如何保证消息不丢
- 确认机制:生产者在发送消息时可以设置
acks参数,当设置为all或者-1时,只有当Leader和所有的Follower都确认接收到消息后,才认为消息发送成功。 - 复制机制:Kafka通过副本机制保证即使一个Broker宕机,消息也不会丢失。每个分区的数据会有多个副本,一个副本作为Leader,其余的作为Follower。只有Leader副本负责处理客户端请求,其他Follower副本会从Leader复制数据。
- 持久化存储:Kafka会将消息持久化到本地磁盘,即使Kafka服务重启,消息也不会丢失。
- 校验和机制:Kafka会校验发送的消息,如果消费者接收到的消息校验和与发送时不一致,那么会认为这个消息已经损坏,会尝试重新拉取消息。
Kafka如何保证消息不重复
Kafka 保证消息不重复主要依靠以下机制:
- 消息的唯一标识:Kafka 中的每条消息都有一个唯一的 offset,表示该消息在分区中的位置。
- 生产者幂等性:生产者在发送相同的消息时,Kafka 集群会识别并丢弃重复的消息。
- 消费者位移管理:Kafka 的消费者会维护自己消费消息的位置,即消费位移,以防止重复消费。
要实现消息不重复,你需要确保以下配置:
- 在生产者端设置
enable.idempotence为true,这将启用幂等性。 - 设置合适的
acks配置,确保消息能够安全到达至少一个副本。 - 确保不会手动提交已消费消息的 offset,除非你明确知道要这么做。
Kafka如何保证消息有序
- 分区机制:
Kafka的核心机制之一是分区(Partition)。每个主题(Topic)可以被分割成多个分区,而消息在发布时会被追加到特定的分区中。在每个分区内部,消息是按照它们被追加的顺序来存储的,因此保证了分区内的消息顺序性。
- 分区器:
生产者(Producer)在发送消息时可以指定一个分区器(Partitioner)来决定消息应该发送到哪个分区。分区器通常基于消息的某个属性(如key的哈希值)来决定分区。这样,具有相同key值的消息会始终被发送到同一个分区,从而确保了这些消息的顺序性。
- 消息key:
生产者可以通过为消息设置特定的key来确保消息的顺序。例如,如果业务逻辑要求相同用户的消息保持顺序,那么生产者可以使用用户ID作为消息的key。这样,所有来自同一用户的消息都会被发送到同一个分区,并按顺序存储和消费。
- 消费者组配置:
在消费者组(Consumer Group)中,每个分区通常只会被一个消费者实例消费。这意味着,如果生产者确保了消息在分区内的顺序性,那么消费者也将按照相同的顺序消费这些消息。这要求消费者组配置得当,确保每个分区只被一个消费者消费。
- 副本同步:
Kafka中的每个分区都有多个副本,其中一个作为领导者(Leader),其他作为追随者(Follower)。当生产者发送消息时,它首先写入领导者副本,然后领导者将消息复制到追随者副本。只有当领导者和所有追随者都确认收到消息后,生产者才会认为消息发送成功。这种同步机制确保了即使发生故障,消息的顺序性也能得到保持。
综上所述,Kafka通过分区、分区器、消息key、消费者组配置以及副本同步等机制来确保消息的顺序性。然而,值得注意的是,Kafka只保证单个分区内的消息顺序,跨分区的消息顺序性则不受保证。因此,在设计Kafka应用时,需要根据业务需求合理设计分区和消息key,以确保消息的顺序性得到满足。
文档信息
- 本文作者:Ling He
- 本文链接:https://GoggleHe.github.io/2024/04/26/Kafka/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)