Kafka學習筆記之入門篇

消息

Kafka的數據單元被稱爲消息。消息由字節數組組成。消息可以有一個可選的元數據,也就是鍵,鍵也是一個字節數組。當消息以一種可控的方式寫入不同的分區時,會用到鍵。最簡單的例子就是爲鍵生成一個一致性散列值,然後使用散列值對主題分區進行取模,爲消息選取分區。這樣可以保證具有相同鍵的消息總是被寫到相同的分區上。

消息批次

爲了提高效率,消息被分批次寫入Kafka。批次就是一組消息,這些消息屬於同一個主題和分區。如果每一個消息都單獨穿行於網絡,會導致大量的網絡開銷,把消息分成批次傳輸可以減少網絡開銷。不過,這要在時間延遲和吞吐量之間做出權衡:批次越大,單位時間內處理的消息就越多,單個消息的傳輸時間就越長。批次數據會被壓縮,這樣可以提升數據的傳輸和存儲能力,但要做更多的計算處理。

消息格式

對於Kafka來說,消息不過是晦澀難懂的字節數組,所以有人建議用一些額外的結構來定義消息的內容,讓它們更易於理解,比如像JSON、XML、Apache Avro和Google Protocolbuf等。

主題(Topic)

Kafka的消息通過主題進行分類,主題就好比數據庫的表,或者文件系統裏的文件夾。

分區

主題可以被分爲若干個分區,消息以追加的方式寫入分區,然後以先入先出的順序讀取,個人認爲可以把分區理解成隊列。要注意,由於一個主題一般包含幾個分區,因此無法在整個主題範圍內保證消息的順序,但可以保證消息在單個分區內的順序。Kafka通過分區來實現數據冗餘和伸縮性,分區可以分佈在不同的服務器上,也就是說,一個主題可以橫跨多個服務器,以此來提升比單個服務器更強大的性能。
在這裏插入圖片描述

生產者

概覽

生產者創建消息。默認情況下,生產者把消息均勻的分佈在主題的所有分區上,而並不關心特定消息會被寫到哪個分區。不過也可以把消息寫到指定的分區,這通常是通過消息鍵和分區器來實現的,分區器爲鍵生成一個散列值,並將其映射到指定的分區上。生產者也可以使用自定義的分區器。生產者發送消息示意圖如下:
在這裏插入圖片描述
我們從創建一個ProducerRecord對象開始,ProducerRecord對象需要包括目標主題和要發送的內容,我們還可以指定鍵或分區。
接下來,數據被傳給分區器。如果之前在ProducerRecord對象裏指定了分區,那麼分區器什麼都不做,直接把指定的分區返回;如果沒有指定分區,那麼分區器會根據ProducerRecord對象的鍵來選擇一個分區。選好分區以後,生產者就知道該往哪個主題和分區發送這條記錄了。緊接着,這條記錄被添加到一個記錄批次裏,這個批次裏的所有消息會被髮送到相同的主題和分區上。
如果消息成功寫入Kafka,就返回一個RecordMetaData對象,它包含了主題和分區信息,以及記錄在分區裏的偏移量;如果寫入失敗,則會返回一個錯誤,生產者在收到錯誤之後會嘗試重新發送消息,幾次之後如果還是失敗,就返回錯誤信息。

發送消息方式

發送消息主要有以下三種方式:

  1. 發送並忘記
    把消息發送給服務器,但並不關心它是否正常到達。大多數情況下,消息會正常到達,因爲Kafka是高可用的,而且生產者會自動嘗試重發。不過,使用這種方式有時候也會丟失一些消息。
  2. 同步發送
    我們使用send()方法發送消息,它會返回一個Future對象,調用get()方法進行等待就可以知道消息是否發送成功。
  3. 異步發送
    我們使用send()方法發送消息,並指定一個回調函數,服務器在返回響應時調用該函數。

消費者

消費者和消費者羣組

消費者讀取消息。消費者可以訂閱一個或多個主題。消費者通過檢查消息的偏移量來區分已經讀取過的消息。偏移量是另一種元數據,它是一個不斷遞增的整數值。在給定的分區裏,每個消息的偏移量都是唯一的。
消費者是消費者羣組的一部分,也就是說,會有一個或多個消費者共同讀取一個主題。羣組保證每個分區只能被一個消費者使用。如圖所示羣組中,有3個消費者同時讀取一個主題,其中的兩個消費者各自讀取一個分區,另外一個消費者讀取其他兩個分區。消費者與分區之間的映射通常被稱爲消費者對分區的所有權關係。在這裏插入圖片描述
除了通過增加消費者來橫向伸縮單個應用程序外,還經常出現多個應用程序從同一個主題讀取數據的情況。每個應用程序可以獲取到所有的消息,而不是其中的一部分。只要保證每個應用程序有自己的消費者羣組,就可以讓它們獲取到主題所有的消息。不同於傳統的消息系統,橫向伸縮Kafka消費者和消費者羣組並不會對性能造成負面影響。
在這裏插入圖片描述

分區再均衡

當一個新的消費者加入羣組或者當一個消費者掛掉或者主題添加了新的分區時,會發生分區重分配。分區的所有權從一個消費者轉移到另外一個消費者,這樣的行爲被稱爲再均衡

訂閱主題

消費者訂閱主題時可以使用正則表達式來匹配主題,如果有人創建了新的主題,並且主題的名字與正則表達式匹配,那麼會立即觸發一次再均衡。

消息輪詢

消息輪詢是消費者API的核心,通過一個簡單的輪詢向服務器請求數據。一旦消費者訂閱了主題,輪詢就會處理所有的細節,包括羣組協調、分區再均衡、發送心跳和獲取數據。輪詢不只是獲取數據那麼簡單。在第一次調用新消費者的poll()方法時,它會負責查找GroupCoordinator,然後加入羣組,接受分配的分區。如果發生了再均衡,整個過程也是在輪詢期間進行的。當然心跳也是從輪詢裏發出去的。所以,我們要確保在輪詢期間所做的任何處理工作都儘快完成。

提交和偏移量

每次調用poll()方法,總是返回由生產者寫入Kafka但還沒有被消費者讀取過的記錄。消費者可以使用Kafka來追蹤消息在分區裏的位置(偏移量)。我們把更新分區當前位置的操作叫作提交
那麼消費者是如何提交偏移量的呢?消費者往一個叫作_consumer_offset的特殊主體發送消息,消息裏包含每個分區的偏移量。再均衡發生的時候,偏移量就起到了作用,因爲完成再均衡之後,每個消費者可能分配到新的分區,而不是之前處理的那個。爲了能夠繼續之前的工作,消費者需要讀取每個分區最後一次提交的偏移量,然後從偏移量指定的地方繼續處理。
如果提交的偏移量小於客戶端處理的最後一個消息的偏移量,那麼處於兩個偏移量之間的消息就會被重複處理,如圖:
在這裏插入圖片描述
如果提交的偏移量大於客戶端處理的最後一個消息的偏移量,那麼處於兩個偏移量之間的消息將會丟失,如圖:
在這裏插入圖片描述

自動提交

將enable.auto.commit設置爲true,那麼每過5s,消費者會自動把從poll()方法接收到的最大偏移量提交上去。提交時間間隔由auto.commit.interval.ms控制,默認值是5s。與消費者裏的其他東西一樣,自動提交也是在輪詢裏進行的。消費者每次在進行輪詢時會檢查是否該提交偏移量了,如果是,那麼就會提交從上一次輪詢返回的偏移量。
使用自動提交無法避免再均衡導致的消息重複消費問題,不過時間間隔越短,重複的消息也越少。
在使用自動提交時,每次提交偏移量時消費者並不知道具體哪些消息已經被處理了,所以在再次調用之前最好確保所有當前調用返回的消息都已經處理完畢(在調用close()方法之前也會進行自動提交)。一般情況下不會有什麼問題,不過在處理異常或提前退出輪詢時要格外小心。

手動提交

同步提交

把auto.commit.offset設置爲false,讓應用程序決定何時提交偏移量。commitSync()在成功提交或碰到無法恢復的錯誤之前會一直重試,使用commitSync()提交偏移量最簡單也最可靠。commitSync()將會提交由poll()返回的最新偏移量,所以在處理完所有記錄後要確保調用了該方法。手動提交也無法避免再均衡發生時消息重複的問題。
commitSync()有一個不足之處,在broker對提交請求作出迴應之前,應用程序會一直阻塞,這樣會限制應用程序的吞吐量。我們可以通過降低提交頻率來提升吞吐量,但如果發生了再均衡,會增加重複消息的數量。

異步提交

commitAsync()是異步提交的方法,支持回調。commitAsync()不會重試,因爲在它收到服務器響應的時候,可能有一個更大的偏移量已經提交成功。

同步和異步組合提交

一般情況下,針對偶爾出現的提交失敗,不進行重試問題不大,因爲如果提交失敗是臨時問題導致的,那麼後續的提交總會有成功。但如果這是發生在關閉消費者或再均衡前的最後一次提交,就要確保能夠提交成功。這時我們可以使用組合提交:

  1. 如果一切正常,我們使用commitAsync()提交。這樣速度更快,而且即使這次提交失敗,下一次提交很可能會成功。
  2. 如果直接關閉消費者,就沒有所謂的“下一次提交了”。使用commitSync()方法會一直重試,直到提交成功或發生無法恢復的錯誤。

提交特定的偏移量

提交偏移量的頻率與處理消息批次的頻率是一樣的。但如果想要更頻繁地提交該怎麼 ?如果poll()方法返回大量數據,爲了避免因再均衡引起的重複處理整批消息,想要在批次中間提交偏移量該怎麼辦?這種情況可以給commitSync()或commitAsync()方法傳參,參數是分區和偏移量的map。

Broker和集羣

一個獨立的Kafka服務器被稱爲broker,broker是集羣的組成部分,每個集羣都有一個broker同時充當了集羣控制器的角色(自動從集羣的活躍成員中選舉出來)。控制器負責管理工作,包括將分區分配給broker和監控broker。在集羣中,一個分區從屬於一個broker,該broker被稱爲分區的首領。一個分區可以分配給多個broker,這個時候會發生分區複製。如果有一個broker失效,其他broker可以接管領導權。
在這裏插入圖片描述

保留消息

保留消息(在一定期限內)是Kafka的一個重要特性。Kafka broker默認的消息保留策略是這樣的:要麼保留一段時間(比如7天),要麼保留到消息達到一定大小的字節數(比如1GB)。當消息數量達到這些上限時,舊消息就會過期並被刪除,所以在任何時刻,可用消息的總量都不會超過配置參數所指定的大小。主題可以配置自己的保留策略,可以將消息保留到不再使用它們爲止。

參考資料

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