kafka-high-reliability

123 阅读5分钟

摘要

Kafka能够存储大量的消息并将其持久化到磁盘上,那么必然是需要解决消息丢失的问题的。其实之前的基础知识 中已经简单介绍了下分区和副本的概念,本文主要介绍了KafKa的副本同步机制,详细讲解了Kafka是如何实现不丢失消息的

涉及名词

Replica:副本

ISR:同步状态的备份的集合 (a set of in-sync replicas)

HW:replica高水印值,副本中最新一条已提交消息的位移

LEO:日志末端位移

如果疑议,欢迎gitee 提 issue,共同进步

日志备份

如果想要数据不出现单点丢失的问题,那么就是一定要做备份,而kafka 的消息都是存储在日志文件中的,所以Kafka的备份叫做日志备份,也就是副本机制。

备份有两种方式

  1. 同步备份,即所有副本同步好了之后,才算提交成功,这种方式及其影响性能
  2. 异步备份,即Leader节点备份好了之后就算成功,此时如果Leader在其他节点同步之前挂了,那么消息有可能丢失

为了解决这个问题,开发者们在Kafka中引入了ISR(同步状态的备份的集合),这个集合包含着和副本Leader保持着高度一致的副本。更直白的说,就是只有在这个集合内的副本,才能够在Leader异常时,参与竞选Leader。与之对应的,就是那些不在这个集合里的副本,为了便于区分,ISR之外的副本叫做OSR(Out-of Replica)。

在基础概念的文章中,我们提到Producer会向Kafka集群发送消息,但是并没有涉及细节。Kafka集群的处理逻辑如下

  1. Broker Controller收到请求
  2. 发送给分区Leader副本,Leader正常存好(LEO+1)
  3. Broker Contriller 通知所有其他副本从Leader 获取消息
  4. 假设此时有两个副本R1,R2,并且都在ISR内
    1. R1 获取了leader 的所有消息,二者完全一致,则R1 加入ISR,同时Leader 标记HW+1,标示HW之前的消息都可被消费了,因为已经存好了
    2. R2 获取Leader 的一部分消息,则R2被踢出ISR集合,之后再找机会慢慢同步
  5. 回复Producer,消息存储成功

所以分区的逻辑架构整体看起来是这样的,而每一个副本分布在不同的Broker上,则保证了不会因为单台机器异常,导致数据丢失

kafka-00-partition

异常逻辑

正常选举

主要是指Leader 异常了怎么选举新的Leader,逻辑很简单,就是由ISR内的副本进行抢占式选举,逻辑如下

  1. Broker Controller 发现Leader副本异常(没有定时汇报,无法通信),同时所有ISR副本进行选举
  2. ISR 内的副本去ZK上抢占注册
  3. Broker Controller 会把新Leader的信息同步给所有副本

异常选举

ISR 为空怎么办?这种状态下的选举叫做 UnClean 选举,可以通过 Broker 的配置 unclean.leader.election.enable 进行开关控制,一般不建议打开,因为这种情况下,数据很可能不一致。不过可以保证集群可用,这就涉及到CAP了,需要权衡

总结

Kafka的备份机制既不是同步备份,也不是异步备份,而是做出了权衡,既保证了性能,又保证了效率。

其他细节

  1. ISR 判断标准
    1. replica.lag.time.max.ms Follower 副本能够落后 Leader 副本的最长时间间隔,当前默认值是 10 秒。这就是说,只要一个 Follower 副本落后 Leader 副本的时间不连续超过 10 秒,那么 Kafka 就认为该 Follower 副本与 Leader 是同步的,即使此时 Follower 副本中保存的消息明显少于 Leader 副本中的消息。
  2. ISR的管理最终都会反馈到Zookeeper节点上。具体位置为:**/brokers/topics/[topic]/partitions/[partition]/state。**目前有两个地方会对这个Zookeeper的节点进行维护:
    1. Controller来维护:Kafka集群中的其中一个Broker会被选举为Controller,主要负责Partition管理和副本状态管理,也会执行类似于重分配partition之类的管理任务。在符合某些特定条件下,Controller下的LeaderSelector会选举新的leader,ISR和新的leader_epoch及controller_epoch写入Zookeeper的相关节点中。同时发起LeaderAndIsrRequest通知所有的replicas。
    2. Leader来维护:leader有单独的线程定期检测ISR中follower是否脱离ISR, 如果发现ISR变化,则会将新的ISR的信息返回到Zookeeper的相关节点中。
  3. 同步相关的配置

server 配置

  rerplica.lag.time.max.ms=10000
  # 如果leader发现flower超过10秒没有向它发起fech请求,那么leader考虑这个flower是不是程序出了点问题
  # 或者资源紧张调度不过来,它太慢了,不希望它拖慢后面的进度,就把它从ISR中移除。

topic配置

min.insync.replicas=1 # 需要保证ISR中至少有多少个replica

producer配置

request.required.asks=0
  # 0:相当于异步的,不需要leader给予回复,producer立即返回,发送就是成功,
      那么发送消息网络超时或broker crash(1.Partition的Leader还没有commit消息 2.Leader与Follower数据不同步),
      既有可能丢失也可能会重发
  # 1:当leader接收到消息之后发送ack,丢会重发,丢的概率很小
  # -1:当所有的follower都同步消息成功后发送ack.  丢失消息可能性比较低