Kafka Broker可靠性
Broker有3個配置引數會影響Kafka訊息儲存的可靠性。這3個引數可以應用在Broker級別,控制所有主題的行為,也可以應用在主題級別,用於控制個別主題的行為。
1.複製係數
主題級別的配置引數是replication.factor,而Broker級別可以通過default.replication.factor來配置自動建立的主題。即使在主題建立之後,也可以通過新增或移除副本來改變複製引數。
如果複製係數為N,那麼在N-1個Broker失效的情況下,仍能從主題讀取資料或者向主題寫入資料。所以,更高的複製係數會帶來更高的可用性、可靠性和更少的故障。但是,複製係數N需要至少N個Broker,而且會有N個數據副本,即會佔用N倍的磁碟空間。在叢集可用性和儲存硬體成本之間做出權衡,一般設定複製係數為3。
副本的分佈也很重要。預設情況下,Kafka會確保分割槽的每個副本放在不同的Broker上。但是,如果不同的Broker位於同一個機架,一旦機架的交換機發生故障,分割槽就會不可用,這時複製係數設定為多少都不管用。為了避免機架級故障,應該把Broker分佈在多個不同的機架上,並使用broker.rack引數來為每個Broker分配所在機架的名字。如果配置了機架名字,Kafka會保證分割槽的副本被分配在多個機架的不同Broker上,從而獲得更高的可用性。
2.不完全的leader選舉
unclean.leader.election.enable只能在broker級別進行配置,預設值為true。
當一個分割槽leader不可用時,一個同步副本會被選為新leader。如果在選舉過程中沒有丟失資料,即生產者提交的資料同時存在於所有同步副本上,那麼這個選舉就是完全的。
但是如果在分割槽leader不可用時,其他副本都是不同步的,怎麼辦?考慮下邊兩個場景:
- 分割槽有3個副本,其中兩個跟隨副本不可用(比如由2個Broker發生崩潰)。這個時候,如果生產者繼續往leader寫入資料,所有訊息都會得到確認並提交。現在假設分割槽leader也不可用了,這個時候如果之前的一個跟隨者重新啟動,它就成為了分割槽的唯一不同步副本。
- 分割槽有3個副本,因為網路問題導致兩個跟隨副本複製訊息滯後,所以,儘管它們還在複製訊息,但已經不同步的。leader作為唯一的同步副本繼續接受訊息。此時,如果leader變為不可用,另外兩個副本就再也無法變成同步的了。
當出現以上兩種情況時,我們面臨兩難的選擇:
- 如果不同步的副本不能被提升為新leader,那麼分割槽在舊leader(最後一個同步副本)恢復之前是不可用的。有時候這種情況會持續數個小時,比如更換記憶體晶片。
- 如果不同步的副本可以被提升為新leader,那麼在這個副本變為不同步後寫入舊leader的訊息會全部丟失,導致資料不一致。假設在副本0和副本1不可用時,offset為100-200的資料被寫入副本2(leader)。現在副本2變為不可用,而副本0重新變為可用。副本0只包含offset為0-100的訊息,不包含100-200的訊息。如果我們允許副本0成為新leader,生產者可以繼續寫入資料,消費者可以繼續讀資料。於是,新首領就有了offset為100-200的新訊息。這樣,部分消費者會讀到offset為100-200的舊訊息(副本2上的訊息),部分消費者會讀到offset為100-200的新訊息(副本0上的訊息),還有部分消費者會讀到二者混和的訊息(部分副本2的舊訊息和部分副本0的新訊息)。另外,副本2可能會重新變為可用的,併成為副本0的跟隨者,此時,副本2會把比副本0舊的訊息全部刪除,而這些訊息對於所有消費者來說都是不可用的。這樣就會出現資料不一致和資料丟失的風險。
對資料一致性和資料質量要求很高的系統,可用把unclean.leader.election.enable設定為false,如銀行系統處理支付流水時寧願等待數小時也不能處理錯誤的資料。對可用性要求很高的系統裡,比如實時分析系統,一般會啟用不完全的leader選舉。
3.最少同步副本
在主題級別和broker上,這個引數都是min.insync.replicas,這個引數指定了最少多少個同步副本收到訊息,訊息才是已提交狀態。
如果要確保已提交的資料被寫入不止一個副本,就需要把最少同步副本數量設定為大一點的值,對於一個包含3個副本的主題,如果min.insync.replicas設定為2,那麼至少要存在2個同步副本才能向分割槽寫入訊息,否則生產者向broker傳送訊息,會收到NotEnoughReplicasException異常。當只剩一個同步副本時,消費者仍然可以繼續讀取已有的資料,但是生產者不能再向broker寫入新資料,此時,Broker變為只讀的了,這是為了避免發生不完全選舉時資料的寫入和讀取發生非預期的行為。為了從只讀狀態中恢復,必須讓兩個不可用分割槽中的一個重新變成可用的(比如重新Broker,網路重新聯通),並等待它變為同步的。