Kafka架構深入解析(一)

消息系統通常由生產者(Producer)、消費者(consumer)和消息代理(broker)三大部分組成,生產者會將消息寫入消息代理、消費者會從消息代理中讀取消息。對於消息代理而言,生產者和消費者都屬於客戶端:生產者和消費者會發送客戶端請求給服務端,服務端的處理分別是存儲消息和獲取消息,最後服務端返回響應結果給客戶端。

 

kafka工作流程及文件存儲機制

kafka中消息是以topic進行分類的,生產者生產消息,消費者消費消息,都是面向topic的。

topic是邏輯上的概念,而partition是物理上的概念。每個partition對應一個log文件,該log文件中存儲的就是producer生產的數據。Producer生產的數據會被不斷追加到該log文件末端,且每條數據都有自己的offset。消費者組中的每個消費者,都會實時記錄自己消費到了哪個offset,以便出錯恢復時,從上次的位置繼續消費。

由於生產者生產的消息會不斷追加到 log 文件末尾,爲防止 log 文件過大導致數據定位

效率低下,Kafka 採取了分片索引機制,將每個 partition 分爲多個 segment。每個 segment

對應兩個文件——“.index”文件和“.log”文件。這些文件位於一個文件夾下,該文件夾的命名

規則爲:topic 名稱+分區序號。例如,first 這個 topic 有三個分區,則其對應的文件夾爲 first-

0,first-1,first-2

索引機制的添加是爲了便於查找。

index log 文件以當前 segment 的第一條消息的 offset 命名。下圖爲 index 文件和 log

文件的結構示意圖。

.index”文件存儲大量的索引信息,“.log”文件存儲大量的數據,索引文件中的元數據指向對應數據文件中 message 的物理偏移地址

kafka生產者

分區策略

如果沒有提前創建消息所屬的主題,默認情況下主題的分區數量只有一個。一個主題只有一個分區時,會導致同一個主題的所有消息都會保存到一個節點上。一般我們會提前創建主題,指定更多的分區數,這樣同一個主題的所有消息就會分散在不同的節點上。

  • 分區的原因

1.方便在集羣中擴展,每個Partition可以通過調整以適應它所在的機器,而一個topic又可以有多個Partition組成,因此整個集羣就可以適應任意大小的數據了;

2.可以提高併發,因爲可以以Partition爲單位讀寫了。

  • 分區的原則

我們需要將 producer 發送的數據封裝成一個 ProducerRecord 對象。

1.指明partition的情況下,直接將指明的值直接作爲partition值。

2.沒有指明partition值只有key的情況下,將key的hash值與topic的partition數進行取餘得到partition值;

3.既沒有partition值又沒有key值的情況下,第一次調用時隨機生成一個整數(後面每次調用在這個整數上自增),將這個值與topic可用的partition總數取餘得到partition值,也就是常說的round-robin算法。

數據可靠性的保證

爲保證 producer 發送的數據,能可靠的發送到指定的 topictopic 的每個 partition 收到

producer 發送的數據後,都需要向 producer 發送 ackacknowledgement 確認收到),如果

producer 收到 ack,就會進行下一輪的發送,否則重新發送數據。

副本數據同步策略

方案 優點 缺點
半數以上完成同步,就發送ack 延遲低 選舉新的leader時,容忍n臺節點的故障,需要2n+1個副本
全部完成同步,才發送ack 選舉新的leader,容忍n臺節點的故障,需要n+1個副本 延遲高

 

1.同樣爲了容忍 n 臺節點的故障,第一種方案需要 2n+1 個副本,而第二種方案只需要 n+1

個副本,而 Kafka 的每個分區都有大量的數據,第一種方案會造成大量數據的冗餘。

2.雖然第二種方案的網絡延遲會比較高,但網絡延遲對 Kafka 的影響較小。

ISR

採用第二種方案之後,設想以下情景:leader 收到數據,所有 follower 都開始同步數據,

但有一個 follower,因爲某種故障,遲遲不能與 leader 進行同步,那 leader 就要一直等下去,

直到它完成同步,才能發送 ack。這個問題怎麼解決呢?

 

Leader 維護了一個動態的 in-sync replica set (ISR),意爲和 leader 保持同步的 follower

合。當 ISR 中的 follower 完成數據的同步之後,leader 就會給 follower 發送 ack。如果 follower

長時間 未 向 leader 同 步 數 據 , 則 該 follower 將 被 踢 出 ISR , 該 時 間 閾 值 由replica.lag.time.max.ms 參數設定。Leader 發生故障之後,就會從 ISR 中選舉新的 leader

ack應答機制

對於某些不太重要的數據,對數據的可靠性要求不是很高,能夠容忍數據的少量丟失,

所以沒必要等 ISR 中的 follower 全部接收成功。

所以 Kafka 爲用戶提供了三種可靠性級別,用戶根據對可靠性和延遲的要求進行權衡,

選擇以下的配置。

acks參數配置:

acks:

0producer 不等待 broker ack,這一操作提供了一個最低的延遲,broker 一接收到還

沒有寫入磁盤就已經返回,當 broker 故障時有可能丟失數據

1producer 等待 broker ackpartition leader 落盤成功後返回 ack,如果在 follower

同步成功之前 leader 故障,那麼將會丟失數據; 

ack=1數據丟失案例:

-1(all):

producer 等待 broker ackpartition leader follower 全部落盤成功後才 返回 ack。但是如果在 follower 同步完成後,broker 發送 ack 之前,leader 發生故障,那麼會

造成數據重複

ack=-1數據重複案例:

故障處理細節

LEO:指的是每個副本最大的 offset

HW:指的是消費者能見到的最大的 offsetISR 隊列中最小的 LEO

  • Follow故障

follow發生故障hou會被臨時提出ISR,待該follower恢復後,follower會讀取本地磁盤記錄的上次的HW,並將log文件高於HW的部分截取掉,從HW開始向leader進行同步,等該follower的LEO大於該Partition的HW,即follower追上leader之後,就可以重新加入ISR了。

  • leader故障

leader發生故障之後,會從ISR中重新選取一個新的leader,之後,爲保證多個副本之間的數據一致性,其餘的follower會先將各自的log文件高於HW部分截掉,然後從新的leader同步數據。

ps:這隻能保證副本之間的數據的一致性,並不能保證數據不丟失或者不重複。

Exacty Once語義

將服務器的ack級別設置爲-1,可以保證Producer到Server之間不會丟失數據,即At Least Once語義。相對的,將服務器ACK級別設置爲0,可以保證生產者每條消息只會被髮送一次,即At More Once語義。

At Least Once 可以保證數據不丟失,但是不能保證數據不重複;相對的,At More Once可以保證數據不重複,但是不能保證數據不丟失,即Exactly Once語義。在0.11版本以前的kafka,對此也無能爲力,只能保證數據的不丟失,再在下游消費者對數據做全局去重。對於多個下游應用的情況,每個都需要單獨做全局去重,這對性能造成了造成了很大的影響。

0.11版本的kafka,引入了一項重大特性:冪等性。所謂的冪等性就是指Producer不論向Server發送了多少次重複的數據,Server端都只會持久化一條。冪等性結合At Lease Once語義,就構成了Kafka的Exactly Once語義。即:

At Least Once+冪等性=Exactly Once

需啓動冪等性,只需要將Producer的參數中enable.idompotence設置爲true即可。Kafka的冪等性實現其實就是將原來的下游需要做的去重放在了數據上游。開啓冪等性的Producer在初始化的時候會被分配PID,發往同一Partition的消息會附帶Sequence Number。而Broker端會對<PID,Partition,SeqNumber>做緩存,當具體相同主鍵的消息提交時,Broker只會持久化一條。

但是PID重啓就會變化,同時不同的Partition也具有不同主鍵,所以冪等性無法保證跨分區跨會話的Exactly Once。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章