kafka isr副本管理机制与exactly once
一句话概述:
isr机制通过为维护一个与leader副本保持“同步状态”的集合,保证数据的一致性,提升了同步性能;ack机制与幂等性保证了数据的exactly once。
引入isr的原因
kafka并未采取Zab和Paxos协议的多数投票机制来来保证主备数据的一致性,而是提出了isr(in-sync- replicas)机制保证数据的一致性。
- 多数投票机制,如果副本数是2f+1,那么最多允许f个副本发生故障;
- isr机制,如果副本数是f+1,那么最多允许f个副本发生故障;
相同容错指标下,位符的副本数量越多,则副本同步的效率也就越低。
几个核心概念:
- LEO :每个副本都有的一个参数,表示当前副本的最后一个offset(Log End Offset)。
- HW :同一个分区下所有副本共享的一个参数,表示所有副本的LEO的最小值,消费者只能消费这个offset之前的值。
- AR :所有部分的集合
- ISR :保持与leader副本“同步”的集合,是AR的子集;该集合是动态变化的,落后过多的副本会被踢出ISR,追上来的副本会被加入到ISR集合中。
故障处理机制
- follower故障
follower发生故障后会被临时踢出ISR,待该follower恢复后,follower会读取本地磁盘记录的上次的HW,并将log文件高于HW的部分截取掉,从HW开始向leader进行同步。等该follower的LEO大于等于该Partition的HW,即follower追上leader之后,就可以重新加入ISR了。 - leader故障
leader发生故障之后,会从ISR中选出一个新的leader,之后,为保证多个副本之间的数据一致性,其余的follower会先将各自的log文件高于HW的部分截掉,然后从新的leader同步数据。
注意:这只能保证副本之间的数据一致性,并不能保证数据不丢失或者不重复。
如何实现exactly once
消息传递过程中的通用概念:
- 最多一次(at most once): 消息可能丢失也可能被处理,但最多只会被处理一次。可能丢失 不会重复
- 至少一次(at least once): 消息不会丢失,但可能被处理多次。可能重复 不会丢失
- 精确传递一次(exactly once): 消息被处理且只会被处理一次。不丢失 不重复 就一次
ack机制:
kafka中有个参数 ack
0: producer完全不管broker的处理结果 回调也就没有用了 并不能保证消息成功发送 但是这种吞吐量最高
-1或者all: leader broker会等消息写入 并且ISR都写入后 才会响应,这种只要ISR有副本存活就肯定不会丢失,但吞吐量最低。
1: 默认的值 leader broker自己写入后就响应,不会等待ISR其他的副本写入,只要leader broker存活就不会丢失,即保证了不丢失,也保证了吞吐量。
所以设置为0时,实现了at most once,而且从这边看只要保证集群稳定的情况下,不设置为0,消息不会丢失。
但是还有一种情况就是消息成功写入,而这个时候由于网络问题producer没有收到写入成功的响应,producer就会开启重试的操作,直到网络恢复,消息就发送了多次。这就是at least once了。
kafka producer 的参数acks 的默认值为1,所以默认的producer级别是at least once。并不能exactly once。
幂等性:
kafka 0.11.0.0版本引入了idempotent producer机制,在这个机制中同一消息可能被producer发送多次,但是在broker端只会写入一次,他为每一条消息编号去重,而且对kafka开销影响不大。
但是幂等性只能保证单个分区的exactly once。
而多分区的情况,我们需要保证原子性的写入多个分区,即写入到多个分区的消息要么全部成功,要么全部回滚。
这样producer端实现了exactly once,那么consumer端呢?
consumer端由于可能无法消费事务中所有消息,并且消息可能被删除,所以事务并不能解决consumer端exactly once的问题,我们可能还是需要自己处理这方面的逻辑。比如自己管理offset的提交,不要自动提交,也是可以实现exactly once的。
总结:
kafka的多副本以及isr机制保证了数据的一致性,ack机制与幂等性保证了数据的精准一次。