Kafka的ISR机制+日志数据清理

ISR(in-sync replica set)

我们知道Kafka是要等全部的follower同步完成后,才可以发送ack,这时候就有可能出现这这种情况:(1)leader收到数据后,后面的follower就开始同步数据了,但是如果有一个follower出现了故障,就会许久的不可以与leader来进行同步,这样leader就会一直等待下去了,直到它同步完成才会把ack发送出去。但是的话这种情况会大大的让Kafka效率降低,所以ISR就出现了。

什么是ISR

leader会维持一个与其保持同步的replica集合,该集合就是ISR,每一个leader partition都有一个ISR,leader动态维护, 要保证kafka不丢失message,就要保证ISR这组集合存活(至少有一个存活),并且消息commit成功。Partition leader 保持同步的 Partition Follower 集合, 当 ISR 中的Partition Follower 完成数据的同步之后,就会给 leader 发送 ack。如果Partition follower长时间(replica.lag.time.max.ms) 未向leader同步数据,则该Partition Follower将被踢出ISR。Partition Leader 发生故障之后,就会从 ISR 中选举新的 Partition Leader。

ACK的应答机制

Kafka对数据的可靠性要求不是非常的高,就是可以说是容忍那么一丢丢的数据丢失,所以就不用等待ISR里的Follower全部接收成功。所以的话Kafka提供了三种可靠性的级别。

acks=0: producer不等待broker的ack,这一个操作是提供了最低的一个延迟,使得broker一接收到还没来得及写入磁盘的时候就已经返回了,当broker出现故障的时候就会可能丢失数据。

acks=1: producer等待broker的ack,partition的leader落盘成功以后返回了ack,如果follwer它在同步成功之前发生了故障的话,那么就会把数据丢失掉。

acks=-1: producer等待broker的ack,partition的leader和follower需要全部落盘成功之后才会返回ack,但是如果在follower同步完成之后,在broker在发送ack前,leader发生了故障,那么这刻会造成数据的重复。

HighWatermark的作用

保证消费数据的一致性和副本数据的一致性。

假设没有HW,消费者消费leader到15,下面消费者应该消费16。

此时leader挂掉,选下面某个follower为leader,此时消费者找新leader消费数据,发现新Leader没有16数据,报错。

HW(High Watermark)是所有副本中最小的LEO。

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自己不会截掉),然后从新的leader同步数据。

Kafka的中的日志数据清理你知道多少

如果让你去设计这个日志删除策略,你会怎么设计?

(1)内部有个定时任务检测删除日志,默认是5分钟 log.retention.check.interval.ms

(2)支持配置策略对数据清理

(3)根据segment单位进行定期清理

启用cleaner

log.cleaner.enable=true

log.cleaner.threads = 2 (清理线程数配置)

日志删除

log.cleanup.policy=delete

清理超过指定时间的消息,默认是168小时,7天,

还有log.retention.ms, log.retention.minutes, log.retention.hours,优先级高到低

log.retention.hours=168

超过指定大小后,删除旧的消息,下面是1G的字节数,-1就是没限制

log.retention.bytes=1073741824

还有基于日志起始位移(log start offset),未来社区还有更多

基于【时间删除】 日志说明

配置了7天后删除,那7天如何确定呢?

每个日志段文件都维护一个最大时间戳字段,每次日志段写入新的消息时,都会更新该字段

一个日志段segment写满了被切分之后,就不再接收任何新的消息,最大时间戳字段的值也将保持不变

kafka通过将当前时间与该最大时间戳字段进行比较,从而来判定是否过期

基于【大小超过阈值】 删除日志说明

假设日志段大小是500MB,当前分区共有4个日志段文件,大小分别是500MB,500MB,500MB和10MB

10MB那个文件就是active日志段。

此时该分区总的日志大小是3*500MB+10MB=1500MB+10MB

如果阈值设置为1500MB,那么超出阈值的部分就是10MB,小于日志段大小500MB,故Kafka不会执行任何删除操作,即使总大小已经超过了阈值;

如果阈值设置为1000MB,那么超过阈值的部分就是500MB+10MB > 500MB,此时Kafka会删除最老的那个日志段文件

注意:超过阈值的部分必须要大于一个日志段的大小

log.retention.bytes和log.retention.minutes任意一个达到要求,都会执行删除

日志压缩

log.cleanup.policy=compact 启用压缩策略

按照消息key进行整理,有相同key不同value值,只保留最后一个

猜你喜欢

转载自juejin.im/post/7084062283453693965