数据可靠性
当producer发送消息给kafka集群,如何保证数据发送过去了呢? 这就需要kafka集群在收到消息时给producer一个反馈, 当producer收到这个反馈就说明消息发送成功, 如果没有收到就反馈,就说明消息发送失败,需要重发!
kafka 集群发送的这个反馈称为ack,但是什么时机发送这个ack呢? 这个ack的发送机制有以下3种情况:
- 当消息发送给某个partition的leader,当这个leader收到这个消息,就直接发送ack;
- 当消息发送给某个partition的leader,然后等它的全部follower都从leader那里同步完获取消息后,再发送ack;
- 当消息发送给某个partition的leader,然后等它的其中一部分follower从leader那里同步获取完消息后,就发送ack;
3种方式各有各的好处与优缺点:
第1种:是光leader收到消息,万一follower没收到消息,然后leader挂了,数据丢失了; 但好处是延迟低;
第2种:是当全部的follower都收到消息再发ack,这个消息是有了,但是延迟高;
第3种:这中方式也是kafka采用的方式, 当leader收到消息后,再等其中一部分follower同步获取完消息,那么就发送ack; 这样也算是一种折中的办法; 但问题是,这里的其中一部分follower该怎么确定呢? 于是就有了ISR,ISR机制被成为“不丢消息”机制; ISR的逻辑就是:从全部的follower中根据某个配置规则选出一些来,例如和leader通信较好的,或者同步数据比较快(数据同步时与leader的数据差距最小), 这样选出一些follower来,当这些follower同步获取完到消息后,就直接发送ack; 但是follower的情况是在变化的, 有时候某台follower有问题了(挂了或卡了或延迟太久), 例如和leader 的通信断掉了,或者同步消息进行的很慢(与leader的数据差距较大),这样的follower就踢出ISR的队列;
总结: kafka用一种比较折中的算法,用ISR算法,既保证了数据的可靠性,又降低了kafka的延迟;
ps: 选取某些follower时,是根据以下这两个配置规则来的:
replica.log.max.messages 默认值是10000条消息;
replica.log.time.max.ms 默认值是10000毫秒;
当follower有了延迟,与leader 的数据量同步差距扩大的10000条消息记录时,该follower就被踢出ISR;
当follower与leader的心跳消息超过10秒,说明该节点有可能是挂掉了,该follower就被踢出ISR;
注:在新的版本中,replica.log.max.messages 配置已经被removed了,不再考虑这个配置了;只保留了rerplica.lag.time.max.ms设置;
本文关键点:
- topic下的每个partition都有副本,其中一个是leader,其他的是follower;
- follower是主动从leader那里fetch(获取)数据;
- leader都会维持一个与其保持同步的replica集合,该集合就是ISR;
- 我们要保证kafka不丢失message,就要保证ISR这组集合存活(至少有一个存活),并且消息commit成功。
- ISR队列是动态的,随时在变的;
对于某些不太重要的数据,对数据的可靠性要求不高,允许丢失某些数据,所以没必要完全等ISR队列的follower全部接受完数据才发ack; 所以kafka为我们提供了3种级别的可靠性, 可以根据实际情况进行配置:
ack = 0,producer只管发数据,不等消息是否真正写成功;
ack = 1, producer等leader接受成功就行了,如果leader故障,会导致数据丢失;
ack= -1,producer等leader和follower全部都接受成功后才返回ack,但是如果当消息都发送成功,却恰好在此时leader挂了, 也就没法给producer发送反馈ack了, 然后producer会认为数据发送失败(实际却是成功了的),导致数据重复;