數(shù)據(jù)可靠性
當(dāng)producer發(fā)送消息給kafka集群,如何保證數(shù)據(jù)發(fā)送過去了呢? 這就需要kafka集群在收到消息時給producer一個反饋, 當(dāng)producer收到這個反饋就說明消息發(fā)送成功, 如果沒有收到就反饋,就說明消息發(fā)送失敗,需要重發(fā)!
kafka 集群發(fā)送的這個反饋稱為ack,但是什么時機(jī)發(fā)送這個ack呢? 這個ack的發(fā)送機(jī)制有以下3種情況:
- 當(dāng)消息發(fā)送給某個partition的leader,當(dāng)這個leader收到這個消息,就直接發(fā)送ack;
- 當(dāng)消息發(fā)送給某個partition的leader,然后等它的全部follower都從leader那里同步完獲取消息后,再發(fā)送ack;
- 當(dāng)消息發(fā)送給某個partition的leader,然后等它的其中一部分follower從leader那里同步獲取完消息后,就發(fā)送ack;
3種方式各有各的好處與優(yōu)缺點:
第1種:是光leader收到消息,萬一follower沒收到消息,然后leader掛了,數(shù)據(jù)丟失了; 但好處是延遲低;
第2種:是當(dāng)全部的follower都收到消息再發(fā)ack,這個消息是有了,但是延遲高;
第3種:這中方式也是kafka采用的方式, 當(dāng)leader收到消息后,再等其中一部分follower同步獲取完消息,那么就發(fā)送ack; 這樣也算是一種折中的辦法; 但問題是,這里的其中一部分follower該怎么確定呢? 于是就有了ISR,ISR機(jī)制被成為“不丟消息”機(jī)制; ISR的邏輯就是:從全部的follower中根據(jù)某個配置規(guī)則選出一些來,例如和leader通信較好的,或者同步數(shù)據(jù)比較快(數(shù)據(jù)同步時與leader的數(shù)據(jù)差距最小), 這樣選出一些follower來,當(dāng)這些follower同步獲取完到消息后,就直接發(fā)送ack; 但是follower的情況是在變化的, 有時候某臺follower有問題了(掛了或卡了或延遲太久), 例如和leader 的通信斷掉了,或者同步消息進(jìn)行的很慢(與leader的數(shù)據(jù)差距較大),這樣的follower就踢出ISR的隊列;
總結(jié): kafka用一種比較折中的算法,用ISR算法,既保證了數(shù)據(jù)的可靠性,又降低了kafka的延遲;
ps: 選取某些follower時,是根據(jù)以下這兩個配置規(guī)則來的:
replica.log.max.messages 默認(rèn)值是10000條消息;
replica.log.time.max.ms 默認(rèn)值是10000毫秒;
當(dāng)follower有了延遲,與leader 的數(shù)據(jù)量同步差距擴(kuò)大的10000條消息記錄時,該follower就被踢出ISR;
當(dāng)follower與leader的心跳消息超過10秒,說明該節(jié)點有可能是掛掉了,該follower就被踢出ISR;
注:在新的版本中,replica.log.max.messages 配置已經(jīng)被removed了,不再考慮這個配置了;只保留了rerplica.lag.time.max.ms設(shè)置;
本文關(guān)鍵點:
- topic下的每個partition都有副本,其中一個是leader,其他的是follower;
- follower是主動從leader那里fetch(獲取)數(shù)據(jù);
- leader都會維持一個與其保持同步的replica集合,該集合就是ISR;
- 我們要保證kafka不丟失message,就要保證ISR這組集合存活(至少有一個存活),并且消息commit成功。
- ISR隊列是動態(tài)的,隨時在變的;
對于某些不太重要的數(shù)據(jù),對數(shù)據(jù)的可靠性要求不高,允許丟失某些數(shù)據(jù),所以沒必要完全等ISR隊列的follower全部接受完數(shù)據(jù)才發(fā)ack; 所以kafka為我們提供了3種級別的可靠性, 可以根據(jù)實際情況進(jìn)行配置:
ack = 0,producer只管發(fā)數(shù)據(jù),不等消息是否真正寫成功;
ack = 1, producer等leader接受成功就行了,如果leader故障,會導(dǎo)致數(shù)據(jù)丟失;
ack= -1,producer等leader和follower全部都接受成功后才返回ack,但是如果當(dāng)消息都發(fā)送成功,卻恰好在此時leader掛了, 也就沒法給producer發(fā)送反饋ack了, 然后producer會認(rèn)為數(shù)據(jù)發(fā)送失敗(實際卻是成功了的),導(dǎo)致數(shù)據(jù)重復(fù);