kafka拓扑图
- 消息发送方式
- 指定分区:指定partition字段,直接发往对应分区号
- 轮询策略:消息指定key即key为null时,消息会以轮询的方式发送到各个分区
- 哈希策略:当key不为null时,使用key的哈希值(采用Murmur2Hash算法)对partition数量取模
- 自定义策略:实现Partitioner接口
- 消息生产过程
- producer 先从 zookeeper 的 “/brokers/…/state”节点找到该 partition 的 leader
- producer 将消息发送给该 leader
- leader 将消息写入本地 log
- followers 从 leader pull 消息,写入本地 log 后向 leader 发送 ACK
- 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 参数被移除了)
复制代码
- 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语义
- At Least Once :至少一次,对应ACK级别-1,也就是所有leader和follower都要落盘成功,保证数据不丢失
- At Most Once:最多一次,对应ACK级别0或者1,可能会导致数据丢失。
- 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。
复制代码
消费者和 leader 通信时,只能消费 HW 之前的数据,HW 之后的数据对消费者不可见。
针对这个规则:
- 当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 同步数据。
所以数据一致性并不能保证数据不丢失或者不重复,这是由 ack 控制的。HW 规则只能保证副本之间的数据一致性!