分区策略
1.分区原因
- 方便在集群中扩展,每个分区可以通过调整以适应它所在的机器,而每个topic又可以由多个分区组成,因此整个集群就可以适应任意大小的数据了
- 可以提高并发,,以分区为单位进行读写
2.分区原则
- 指明分区的情况下,直接将指明的值作为分区的值
- 没有指明分区,但有key的情况下,将key的hash值与topic的分区数量进行取余得到分区的值
- 既没有分区值 也没有key值的情况下,第一次调用时随机生成一个整数(后面每次调用在这个整数上自增),将这个值与topic可用的分区总数取余得到分区值,也就是round-robin算法
数据可靠性
为保证生产则发送的数据,能可靠地发送到指定的topic,topic的每个分区收到数据后,都需要向生产者发送acknowledgement确认,若生产者收到ack,就会进行下一轮的发送。否则重新发送数据。
1.副本同步策略
- 半数以上完成同步,就发送ack
- 全部完成同步,才发送ack
kafka选用的是第二种方案
2.ISR
leader维护了一个动态的in-sync replica set(ISR),意为和leader保持同步的follower集合。当ISR中的follow完成数据的同步之后,leader就会给follower发送ack。如果follower长时间未向leader同步数据,则该follower将被剔除ISR,该时间阈值由replica.lag.time.max.ms参数设定。leader发生故障之后,就会从isr中选取新的leader。
3.ack应答机制
三种可靠性级别,用户可以根据对可靠性和延迟的要求,进行配置acks
- 0:生产者不等待broker的ack,这个操作提供了最低的延迟,broker一接收到信息还没有写到磁盘就已经返回,当broker故障时会丢失数据
- 1:生产者等待broker的ack,分区的leader落盘成功后返回ack,如果在follower同步成功之前leader故障,那么将会丢失数据
- -1或all:生产者等待broker的ack,分区的leader和isr中的follower全部落盘之后才返回ack。但是如果在follower同步完成后,broker发送ack之前,leader发生故障,那么会造成数据重复
4.故障处理细节
HW和LEO是保证消费者消费数据的一致性,与存储数据完整性没有关系。
- leader故障
会从isr中选出一个新的leader,为保证多个副本之间的数据一致性,其余的follower会先将各自的log文件高于HW的部分截掉,然后从新的leader同步数据。这只能保证副本之间的数据一致性,并不能保证数据不丢失或者不重复。 - follower故障
follower会被临时踢出ISR,待恢复后,会读取本地磁盘记录的上次的HW,并将log文件高于HW的部分截取掉,从HW开始向leader进行同步。等follower的LEO大于等于该分区的HW,即follower追上leader之后,就可以重新加入ISR了。
5.Exactly Once
作用:避免重复数据
Exactly Once = At Least Once + 幂等性
Producer中的enable.idompotence=true
实质:kafka的幂等性实现其实就是讲原来下游需要做的去重放在了数据上游。
过程:Producer在初始化的时候会被分配一个PID,发往同一个Partition的消息会附带Sequence Number。二Broker端会对<PID,Partition, SeqNumber>做缓存,当具有相同主键的消息提交时,Broker只会持久化一条数据。
注意:幂等性只在一次会话中有效,如果Producer故障之后重新恢复,会被分配不同的PID,此时即使带着相同的数据,Broker端也识别不到是同一个数据。
Producer事务
为了实现跨分区跨会话的事务,需要引入一个全局唯一的Transaction ID,并将Producer获得的PID和Transaction ID绑定。这样当Producer重启后就可以通过正在进行的Transaction ID获得原来的ID。
kafka引入新组件Transaction Coordinator,Producer就是通过这个组件交互获得Transaction ID对应的任务状态。TC还负责将事务所有写入Kafka的一个内部Topic,这样即使整个服务重启,由于事务状态得到保存,进行中的事务状态可以得到恢复。