Kafka设计原理总结
1.生产者分区机制
(1)分区原因
-
提高可扩展性:集群可通过设置Topic的Partition数量,以适应合适大小的数据。
-
提高并发:以Partition为单位读写。
(2)数据分区原则
①直接指明partition值
②不执行partition,而
通过key-value,进行
哈希取余得到partition
③
轮询算法:只有value时,随机生成一个整数值,与Topic可用的partition数量取余。
![](https://img-blog.csdnimg.cn/6669a047eb254b8c97d77600b4f63446.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQnJv5aSn6KGo5ZOl,size_20,color_FFFFFF,t_70,g_se,x_16)
2.生产者可靠性保证
(1)可靠性保证机制
为了保证生产者能可靠的发送到指定的 topic,
topic 的每个partition 收到
生产者发送的数据后,都需要向生产者发送 ack(acknowledgement 确认收到),如果producer 收到 ack,就会进行下一轮的发送,否则重新发送数据。
此时会有两个问题:
-
何时发送ACK? ——首先要确保follower和leader同步完成后再发送ack
-
多少个Follower同步完成后才发送ACK? ——常见两种方案,半数follower同步和全部follower同步
![](https://img-blog.csdnimg.cn/685b5b63bc074b80a8f719920187c973.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQnJv5aSn6KGo5ZOl,size_20,color_FFFFFF,t_70,g_se,x_16)
(2)副本同步策略(默认全部同步)
![](https://img-blog.csdnimg.cn/1b10e00324604e89af82899fece43ef1.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQnJv5aSn6KGo5ZOl,size_20,color_FFFFFF,t_70,g_se,x_16)
首先两种策略的副本数量都是为了保证故障后至少有一个副本可用
①半数同步需要2n+1:加入只有一半保存成功,
那么(2n+1)/2=n+1, 此时n台发生故障,多出来的一台则保证至少一个副本可用。
②全部同步需要n+1: 此时n+1副本全部同步成功,此时n台发生故障,还是多出一个副本可用。
但此时如果follower宕机后,就需要ISR机制恢复。
(3)ISR(in-sync replica set)
如果在follower同步时,
有一个follower故障无法与leader进行同步,如果不处理会导致leader一直等待无法完成同步返回给生产者ACK;
此时Leader内部维护了LSR动态同步队列,follower未在规定replica.lag.time.max.ms 参数阈值时间完成同步,则先踢出ISR。如果是Leader故障则从ISR中选举新的Leader
(4)ACK应答机制保证消息不丢失
①ack=0:
延迟最低。不管broker是否写入磁盘,
只要收到消息立即返回ack。
但broker可能未写入磁盘。
②ack=1(默认值):
只要leader落盘成功则返回,
但follower可能未同步成功。
③ack=-1:可靠性高。
等待leader和follower全部写入成功才返回ACK。
如果follower同步完成后,然后发送ack给生产者之前,leader发送故障。此时生成者会重新发送数据,造成数据重复。
(5)Exactly Once语义保证数据不重复也不丢失
对于一些非常重要的信息,比如说
交易数据,下游数据消费者要求数据既不重复也不丢失,即 Exactly Once 语义。Kafka引入了幂等性,指 Producer 不论向 Server 发送多少次重复数据,Server 端都只会持久化一条。即:
At Least Once + 幂等性 = Exactly Once
①At Least Once就是ACK=-1全部同步,At Most Once就是ACK=0,消息只发送一次。
②幂等性开启需要
将 Producer 的参数中 enable.idompotence 设置为 true 即可,
此时
Producer 在
初始化的时候会被分配一个 PID,发往同一 Partition 的消息会附带 Sequence Number。
Broker端对<PID,Partition,SeqNumber>做缓存,当相同值消息提交时,Broker只持久化一条消息。
但是Producer每次初始化时PID都会变化,而且不同Partition值也不同,
因此幂等性无法保证跨分区和跨会话。
(6)LEO和HW保证数据一致性
-
如果follower发生故障期间,Leader和其他Follower都在同步数据,此时故障follower恢复后数据将不一致
-
同理,Leader发生故障期间,新选举出来的Leader也可能在不断同步数据
![](https://img-blog.csdnimg.cn/da4dd4c0db1549fda0fc0fe2e8d3b21a.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAQnJv5aSn6KGo5ZOl,size_20,color_FFFFFF,t_70,g_se,x_16)
解决思路:
-
LEO:每个副本最大的offset (broker独有)
-
HW:消费者能见到的最大offset,即ISR队列中最小的LEO (共享的)
①如果follower故障
它被临时踢出ISR,待恢复时,
首先读取本地磁盘记录之前的HW,将log文件高于HW部分截取掉,从HW开始部分向leader同步。
直到follower的LEO>=现在partition的HW,即故障节点刚刚追上leader之后,才可以加入ISR(不一定要同步最新的,只需要大于等于消费者可见offset)。
②如果leader故障
首先从ISR中选出新leader,然后其余follower会将它门自己的log文件中,高于HW部分全部截掉,然后从新的Leader中同步数据。