kafka基础:生产与副本同步(一)

kafka拓扑图
kafka拓扑图.png

  • 消息发送方式
  1. 指定分区:指定partition字段,直接发往对应分区号
  2. 轮询策略:消息指定key即key为null时,消息会以轮询的方式发送到各个分区
  3. 哈希策略:当key不为null时,使用key的哈希值(采用Murmur2Hash算法)对partition数量取模
  4. 自定义策略:实现Partitioner接口
  • 消息生产过程
  1. producer 先从 zookeeper 的 “/brokers/…/state”节点找到该 partition 的 leader
  2. producer 将消息发送给该 leader
  3. leader 将消息写入本地 log
  4. followers 从 leader pull 消息,写入本地 log 后向 leader 发送 ACK
  5. leader 收到所有 ISR 中的 replication 的 ACK 后,增加 HW(high watermark,最后 commit 的 offset)并向 producer 发送 ACK
ISR:  
leader维护一个动态的in-sync replica set(ISR),意为和leader保持同步的follower集合。
当 ISR 中的follower 完成数据的同步之后,leader 就会给 follower 发送 ack。  
如果 follower 长时间未向 leader 同步数据,则该 follower 将会被踢出 ISR,  
该时间阈值由 replica.lag.time.max.ms 参数设定。  
leader 发生故障之后,就会从 ISR 中选举新的 leader。  
(之前还有另一个参数,0.9 版本之后 replica.lag.max.messages 参数被移除了)
复制代码

kafka消息生产.png

  • ack应答机制

如上图所示,ISR中的follower主动从leader拉取数据,对于某些不太重要数据,能够容忍数据的少量丢失,所以没必要等 ISR 中的follower全部接收成功。
所以Kafka为用户提供了三种可靠性级别,用户根据对可靠性和延迟的要求进行权衡,选择以下的acks 参数配置(offsets.commit.required.acks)

0:producer 不等待 broker 的 ack,这一操作提供了一个最低的延迟,broker 一接收到,还没有写入磁盘就已经返回,当 broker 故障时有可能丢失数据;
1:producer 等待 broker 的 ack,partition 的 leader 落盘成功后返回 ack,如果在 follower 同步成功之前 leader 故障,那么将会丢失数据;
-1:producer 等待 broker 的 ack,partition 的 leader 和 follower 全部落盘成功后才返回 ack。但是 如果在 follower 同步完成后,broker 发送 ack 之前,leader 发生故障,那么就会造成数据重复。

  • Exactly Once语义
  1. At Least Once :至少一次,对应ACK级别-1,也就是所有leader和follower都要落盘成功,保证数据不丢失
  2. At Most Once:最多一次,对应ACK级别0或者1,可能会导致数据丢失。
  3. Exactly Once:恰好一次,在0.11版本之前kafka对此无能为力,只能保证数据不丢失,靠下游consumer业务端做全局去重,0.11之后引入了重大特性-幂等性,Producer无论发送多少次重复信息,server端只会持久化一条,At Least Once+幂等性=Exactly Once。

启用幂等性需要将Producer中的参数enable.idompotence 设置为 true即可。
开启幂等性的 Producer 在初始化的时候会被分配一个 PID,发往同一 Partition 的消息会附带 Sequence Number。而 Broker 端会对
相同Sequence Number的消息进行去重,但是 PID 重启就会变化,同时不同的 Partition 也具有不同主键,所以幂等性无法保证跨分区会话的 Exactly Once。

  • 故障处理

由于我们并不能保证 Kafka 集群中每时每刻 follower 的长度都和 leader 一致(即数据同步是有时延的),
那么当leader 挂掉选举某个 follower 为新的 leader 的时候(原先挂掉的 leader 恢复了成为了 follower),可能会出现leader 的数据比 follower 还少的情况。为了解决这种数据量不一致带来的混乱情况,Kafka 提出了以下概念:

LEO(Log End Offset):指的是每个副本最后一个offset;
HW(High Wather):指的是消费者能见到的最大的 offset,ISR 队列中最小的 LEO。
复制代码

副本.png

消费者和 leader 通信时,只能消费 HW 之前的数据,HW 之后的数据对消费者不可见。

针对这个规则:

  1. 当follower发生故障时:

follower 发生故障后会被临时踢出 ISR,待该 follower 恢复后,follower 会读取本地磁盘记录的上次的 HW,并将 log 文件高于 HW 的部分截取掉,从 HW 开始向 leader 进行同步。等该follower 的 LEO 大于等于>该 Partition 的 HW,即 follower 追上 leader 之后,就可以重新加入 ISR 了。
follower故障时副本同步.png

  1. 当leader发生故障时:

leader 发生故障之后,会从 ISR 中选出一个新的 leader,之后,为保证多个副本之间的数据一致性,其余的 follower 会先将各自的 log 文件高于 HW 的部分截掉,然后从新的 leader 同步数据。
leader故障时副本同步.png

所以数据一致性并不能保证数据不丢失或者不重复,这是由 ack 控制的。HW 规则只能保证副本之间的数据一致性!

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享