关于Kafka中的ISR机制
ISR 概念
首先ISR的全称为 In-Sync Replicas (同步副本集), 可以理解为与leader保持同步的所有副本的集合(包含 Leader 本身)。一个分区的所有副本集合叫做AR (Assigned Repllicas),与leader-replica未能保持同步的副本集叫做OSR (Out-Sync Relipcas)。
ISR动态维护了一个和leader副本保持同步的副本集合,ISR中的副本全部都和leader的数据保持同步。
为什么要设计 ISR 机制
- ISR 机制通过副本冗余机制,提供了 Kafka 消息的高可靠性。
- ISR 机制可以做到故障转移,保障服务的可用性。
- ISR 平衡了主从架构下,复制方案的选择(同步 / 异步 / 少数服从多数),让使用者根据参数自行选择。
在一些中间件中,都有副本的概念,在不同的场景下写入数据时,要求写入副本的个数也不尽相同。
例如 zk 中要求写入的节点个数大于一半才算成功,或者有些要求高可靠性的场景,规定写入所有副本才能算成功。
而 kafka 的 ISR 可以允许生产消息时,根据自己的业务场景自行配置想要达到的效果:
acks=0:fire and forget,也就是我发了就算完了,后续成不成功我都不管,这种设置下消息的高可靠性几乎没有保障,但是有极大的吞吐量。
acks=1:写入主节点就算成功,这种设置,可以保障一定的高可靠性,也具有不错的吞吐量。
acks=all:也就是写入 ISR 中所有的副本才算成功,这种设置下,就能提供较高的高可靠性,但是吞吐量就相对较低。
我们在考虑生产消息时,ISR 机制可以友好的让使用者根据自己的业务需求去设置参数,去选择自己想要达到什么程度的可靠性,而不是只提供一种可靠性选择。
【什么是失效副本?】
功能失效:节点宕机,在该节点上的副本都属于功能失效副本。
同步失效:follower 副本所在的 broker 因为带宽或者负载等因素无法及时完成同步,导致被踢出 ISR。
ISR 伸缩控制参数
在Kafka 0.9x 版本之前,有一个控制参数:replica.lag.max.messages 默认值为 4000,表示如果 follower 的消息个数落后 leader 个数 4000,那么就会被踢出 ISR 列表;但是这个参数在不同场景下,很难给出一个合理的值。如果设置的很大,那么这个参数也就失去了意义,因为 ISR 列表都不会变动。如果设置的很小,那么在高吞吐的场景下,又会造成 ISR 列表的频繁变动。
因此从Kafka 0.9x 版本开始,移除了该参数。现在用来控制的参数是:replica.log.time.max.ms。 默认值是 10000ms,即 10 秒;也就是说 follower 在 10s 内都没能追上 Leader 的 LEO,就会被踢出 ISR。
说明一下:LEO(log end offset)指日志末端位移,代表日志文件中下一条待写入消息的offset,这个offset上实际是没有消息的。不管是leader副本还是follower副本,都有这个值。当leader副本收到生产者的一条消息,LEO通常会自增1,而follower副本需要从leader副本fetch到数据后,才会增加它的LEO。
ISR 是动态伸缩的,可能出现 follower 全部都挂了,ISR 中只剩下 leader,那么此时设置 acks=all 就等价于 acks=1 了。这样就会对高可靠性要求的场景产生危险,那么 kafka 提供了参数:min.insync.replicas。
这个参数可以配置最少 ISR 中需要多少个副本,才能继续提供写服务。如果设置为 2,一旦 ISR 中的个数小于 2,那么就不再提供写服务,牺牲一定的可用性,来保障这种高可靠的场景需求。
总结
ISR 机制的存在是 kafka 为了平衡可靠性和可用性,不指定提供高可靠或者高可用的服务,而是将决定权交给了使用者,让使用者通过参数来控制,到底要实现什么程度的高可靠与高可用。