Kafka-可靠性保證-保證了哪些可靠性
ACID是關系型資料庫普遍支援的标準可靠性保證。
ACID:原子性(atomicity)、一緻性(consistency)、隔離性(isolation)、持久性(durability)
如果資料庫遵循ACID規範,那麼該資料庫就支援與事務相關的行為。
kafka在哪些方面做出保證?
- 1.kafka可以保證分區消息的順序。如果使用同一個生産者往同一個分區寫入消息,而且消息B在消息A之後寫入,那麼kafka可以保證消息B的偏移量比消息A的偏移量大。而且消費者會先讀取消息A再讀取消息B。
- 2.隻有當消息被寫入分區的所有同步副本時(但不一定要寫入磁盤),它才被認為是”已送出“的。生産者可以選擇接收不同類型的确認,比如在消息被完全送出時的确認,或者在消息被寫入首領副本時的确認,或者在消息被發送到網絡時的确認。
- 3.隻要還有一個副本是活躍的,那麼已經送出的消息就不會丢失
- 4.消費者隻能讀取已經送出的消息。
Kafka-可靠性保證-複制機制
kafka的複制機制和分區的多副本架構是kafka可靠性保證的核心。把消息寫入多個副本可以使kafka在發生崩潰時仍能保證消息的持久性。
kafka的主題被分為多個分區,分區是基本的資料塊。分區存儲在單個磁盤上,kafka可以保證分區裡的事件是有序的,分區可以線上(可用),也可以離線(不可用)。每個分區可以有多個副本,其中一個副本是首領。所有的事件都直接發送給首領副本,或者直接從首領副本讀取事件。其它副本隻需要與首領保持同步,并及時複制最新的事件。當首領副本不可用時,其中一個同步副本将成為新首領。
分區首領時同步副本,而對于跟随者副本來說,他需要滿足以下條件才能被認為是同步的。
- 1.與zookeeper之間有一個活躍的會話,跟随者副本在過去的6s(可配置)内向zookeeper發送過心跳
- 2.在過去的10s内(可配置)從首領那裡擷取過消息
- 3.再過去的10s内從首領那裡擷取過最新的消息。光從首領那裡擷取消息是不夠的,它還必須是幾乎零延遲的。
如果跟随者副本不能滿足以上任何一點,比如與zookeeper斷開連接配接,或者不再擷取新消息,或者擷取消息滞後10s以上,那麼它就被認為是不同步的。一個不同步的副本通過與zookeeper重建立立連接配接,并從首領那裡擷取最新消息,可以重新變成同步的。這個過程在網絡出現臨時問題并很快得到修複的情況下會很快完成,但如果broker發生崩潰就需要較長時間。
一個滞後的同步副本會導緻生産者和消費者變慢,因為在消息被認為已送出之前,用戶端會等待所有同步副本接收消息。而如果一個副本不再同步了,我們就不再關心它是否已經收到消息。雖然非同步副本同樣滞後,但它并不會對性能産生任何影響。但是,更少的同步副本意味着更低的有效複制系數,在發生當機時丢失資料的風險更大。
注意:如果一個或多個副本在同步和非同步狀态之間快速切換,說明叢集内部出現了問題,通常是Java不恰當的垃圾回收配置導緻的。不恰當的垃圾回收配置會造成幾秒鐘的停頓,進而讓broker與zookeeper之間斷開連接配接,最後變成不同步的,進而發生狀态切換。
Kafka-可靠性保證-broker配置
broker有3個配置參數會影響Kafka消息存儲的可靠性。與其它配置參數一樣,它們可以是broker級别的,用于控制所有主題的行為,也可以應用在主題級别,用于控制個别主題的行為。
在主題級别控制可靠性,意味着kafka叢集可以同時擁有可靠的主題和非可靠的主題。
1.複制系數
主題級别的配置參數是replication.factor,而在broker級别則可以通過default.replication.factor來配置自動建立的主題。
假設主題的複制系數都是3,也就是說每個分區總共會被3個不同的broker複制3次。kafka的預設複制系數是3,不過使用者可以對它進行修改。即使是在主題建立之後,也可以通過新增或移除副本來改變複制系數。
如果複制系數為N,那麼在N-1個broker失效的情況下,仍然能夠從主題讀取資料或向主題寫入資料。是以,更高的複制系數會帶來更高的可用性、可靠性和更少的故障。
複制系數為N就需要至少N個broker,而且會有N個資料副本,也就是說他們會占用N倍的磁盤空間。需要在可用性和存儲硬體之間做出權衡。
如何确定一個主體需要幾個副本?要看主題的重要程度,以及願意付出多少成本換去可用性。
如果因broker重新開機導緻的主體不可用是可接受的,那麼把複制系數設為1就可以了。在作出這個權衡的時候,要確定這樣不會對消息使用方造成影響,因為在節省了硬體成本的同時降低了可用性。
建議把複制系數設為3,大多數情況下,這已經足夠安全,也有些銀行會使用5個副本,以防不測。
副本的分布也很重要。預設情況下,kafka會確定分區的每個副本被放在不同的broker上。不過,有時候這樣仍然不夠安全,因為如果這些broker處于同一個機架上,一旦機架的交換機發生故障,分區就會不可用,這時候把複制系數設為多少都不管用。為了避免機架級别的故障,我們建議把broker分布在多個不同的機架上,并使用broker.rack參數來為每個broker配置所在機架的名字。如果配置了機架名字,kafka會保證分區的副本被分布在多個機架上,進而獲得更高的可用性。
2.不完全的首領選舉
unclean.leader.election.enable隻能在broker級别(實際上是在叢集範圍内)進行配置,它的預設值是true。
當分區首領不可用時,一個同步副本會被選為新首領。如果在選舉過程中沒有丢失資料,也就是說送出的資料同時存在于所有的同步副本上,那麼這個選舉就是完全的。
但是也會出現首領不可用時,其它副本都是不同步的情況,如以下場景:
- 分區有3個副本,其中的兩個跟随者副本不可用(比如有兩個broker發生崩潰)。這個時候,如果生産者繼續往首領寫入資料,所有消息都會得到确認并被送出(因為此時首領時唯一的同步副本)。現在我們假設首領也不可用了(又一個broker發生崩潰),這個時候,如果之前的一個跟随者重新啟動,它就成為了分區的唯一不同步副本。
- 分區有3個副本,因為網絡問題導緻兩個跟随者副本複制消息滞後,是以盡管它們還在複制消息,但已經不同步了。首領作為唯一的同步副本繼續接收消息。這個時候,如果首領變為不可用,另外兩個副本就再也無法變成同步的了。
如果出現這兩種場景,那麼就需要做出一個兩難的選擇:
- 如果不同步的副本不能被提升為新首領,那麼分區在舊首領(最後一個同步副本)恢複之前是不可用的。有時候這種狀态會持續數小時(比如更換記憶體晶片)。
- 如果不同步的副本可以被提升為新首領,那麼在這個副本變為不同步之後寫入舊首領的消息會全部丢失,導緻資料不一緻。假設在副本0和副本1不可用時,偏移量100-200的消息被寫入副本2(首領)。現在副本2變為不可用的,而副本0變為可用的。副本0隻包含偏移量0-100的消息,不包含偏移量100-200的消息。如果我們允許副本0稱為新首領,生産者就可以繼續寫入資料,消費者可以繼續讀取消息。于是新首領就有了偏移量100-200的新消息。這樣,部分消費者會讀取到偏移量100-200的舊消息,部分消費者會讀取到100-200的新消息,還有部分消費者讀取到的是二者的混合。這樣會導緻非常不好的結果,比如生成不準确的報表。另外,副本2可能會重新變為可用,并成為新首領的跟随者。這個時候,它會把比目前首領舊的消息全部删除,而這些消息對于所有消費者來說是不可用的。
總結:
如果我們允許不同步的副本成為首領(unclean.leader.election.enable設為true),那麼就要承擔丢失資料和出現資料不一緻的風險。
如果我們不允許不同步的副本成為首領(unclean.leader.election.enable設為false),那麼就要接受較低的可用性,因為我們必須等待原先的首領恢複到可用狀态。
一些對資料品質和資料一緻性要求較高的系統會禁用這種不完全的首領選舉,甯可花點時間等待舊分區首領的恢複,也不接受資料的丢失和資料的不一緻性。
一些對可用性要求較高的系統裡,比如實時點選流分析系統,一般會啟用不完全的首領選舉。