消息顺序性的保证
Kafka 通过分区机制和消息键来保证消息的顺序性。在 Kafka 中,每个 Topic 可以分为多个分区,每个分区内的消息都是有序的。消息在被追加到 Partition(分区)的时候都会分配一个特定的偏移量(offset)。Kafka 通过偏移量(offset)来保证消息在分区内的顺序性。
对于生产者端,因为在同一个分区内,消息是有序的。 因此可以使用消息键和指定分区将相关消息分配到同一分区,可以保证这些消息在同一分区内依然有序。
对于消费者端:消费者在消费消息时,同一个消费者线程只能同时消费一个分区的消息,这样可以保证消费端在处理某个分区内的消息时是按顺序的。如果 Kafka 集群中没有足够的消费者线程,某个消费者线程可能需要同时消费多个分区的消息,但这些分区之间的顺序是无法保证的。
消息可靠性的保证
生产者端的保证
生产者在发送消息时,需要通过消息确认机制来确保消息成功到达。生产者发送消息至 Broker ,需要处理 Broker 的响应,如果 Broker 返回写入失败等错误消息,重试发送。
- 设置合适的重试次数
retries
和重试间隔:决定生产者端的重试次数 - 配置合适的
acks
参数:决定生产者在收到多少个副本的确认后认为消息发送成功。- acks=0:生产者不会等待任何服务器的确认。消息可能会丢失,但性能最高。
- acks=1:生产者会在领导者副本(leader)成功接收到数据后收到确认。数据可靠性得到了基本保障,但如果领导者副本崩溃,仍有可能丢失消息。
- acks=all(或 -1):生产者会等待所有同步副本(ISR)接收到数据后收到确认。数据可靠性最高,但性能会有所下降,因为需要等多个副本都确认接收。
消费者端的保证
消息在被追加到 Partition(分区)的时候都会分配一个特定的偏移量(offset)。偏移量(offset)表示 Consumer 当前消费到的 Partition(分区)的所在的位置。Kafka 通过偏移量(offset)可以保证消息在分区内的顺序性。
自动提交offset会导致以下问题:当消费者拉取到了分区的某个消息之后,消费者会自动提交了 offset。当消费者刚拿到这个消息准备进行真正消费的时候,突然挂掉了,消息实际上并没有被消费,但是 offset 却被自动提交了。
通常的解决方法:手动关闭自动提交 offset,每次在真正消费完消息之后再自己手动提交 offset 。 但是这样会带来消息被重新消费的问题。比如你刚刚消费完消息之后,还没提交 offset,结果自己挂掉了,那么这个消息理论上就会被消费两次。
Broker的保证
Broker通过 多副本机制 来保证消息不丢失。Kafka 中的每个分区都有多个副本(Replicas),这些副本分布在不同的 Broker 上。当一个 Broker 宕机时,其他持有该分区副本的 Broker 能够接管工作。
Kafka 的副本分为leader副本和follower副本。每个主题(topic)中的分区(partition)会有一个leader副本和多个follower副本。
- leader副本:每个 Kafka 分区都有一个 Leader,负责处理所有的读写请求
- follower副本:定期从领导者副本中拉取数据,保持数据的一致性。
当leader副本宕机时,会在follower副本中选出一个新的领导者,确保数据的连续性和可用性。
提示
在 Kafka 中,ISR (In-Sync Replica) 是一组与 Leader 副本保持同步的所有副本。具体来说,ISR 包含那些能够及时复制 Leader 副本中最新消息的副本。ISR 中的副本保证了它们的数据与 Leader 的数据一致或者仅仅落后很少量的数据,这些副本在副本集合中被认为是“同步”的。
一个副本如果长时间无法与 Leader 同步(可能因为网络延迟、故障等原因),它就会被移出 ISR 集合。只有在其再次追上 Leader 后,才会被重新加入 ISR 集合。
选举机制
Kafka的选举有以下几种
- Kafka Controller的选举
- Partition Leader的选举
- Consumer Group Coordinator(消费组协调者)的选举。
Kafka Controller的选举过程
- 启动竞争 :集群启动时,各个 Broker 节点会尝试在 ZooKeeper 中创建一个临时节点
/controller
。ZooKeeper 是一个分布式协调服务,可保障只有一个节点能成功创建该节点。 - 确定控制器 :成功创建
/controller
节点的 Broker 会成为控制器,并在该节点中记录自身的 Broker ID 等信息。 - 故障处理 :若控制器所在节点发生故障,其创建的临时节点会自动消失。其他 Broker 监听到这一变化后,会重新竞争创建
/controller
节点,从而选出新的控制器。
Partition Leader的选举过程
- 控制器主导 :分区首领选举由控制器负责。控制器会维护分区的状态信息,当检测到首领副本不可用时,会触发选举流程。
- 优先副本选择 :Kafka 优先选择分区的优先副本作为首领。优先副本是在分区创建时指定的第一个副本。
- 存活副本选举 :若优先副本不可用,控制器会从同步副本集合(ISR)中选择一个副本作为新的首领。同步副本是指与首领副本保持同步的副本。
- 元数据更新 :选举出新首领后,控制器会更新集群元数据,通知其他 Broker 新的首领信息。
Consumer Group Coordinator(消费组协调者)的选举
- 协调器确定:消费者组中的消费者在启动时,会向 Kafka 集群发送请求,Kafka 根据消费者组 ID 的哈希值选择一个 Broker 作为协调器。
- 注册与通知 :消费者向选定的协调器注册自己,协调器会维护消费者组的成员信息,并将分区分配方案通知给各个消费者。
- 故障处理 :若协调器所在 Broker 故障,消费者会收到通知,重新发起协调器选举。
消息重复消费的处理方案
Kafka中会出现消息重复的情况,根本原因:服务端侧已经消费的数据没有成功提交 offset
严格意义上是无法从根本上解决重复的消息,因为为了保证消息的可靠性会产生重复的消息。只能从业务层面解决重复消息的影响
只有让消费者的处理逻辑具有 幂等性 ,保证无论同一条消息被消费多少次,结果都是一样的,从而避免因重复消费带来的副作用。