理解Kafka offset
日常開發(fā)中,相信大家都對 Kafka 有所耳聞,Kafka 作為一個分布式的流處理平臺,一般用來存儲和傳輸大量的消息數(shù)據(jù)。在 Kafka 中有三個重要概念,分別是 topic、partition 和 offset。
- topic 是 kafka 中的消息以主題為單位進行歸類的邏輯概念,生產(chǎn)者負責將消息發(fā)送到特定的主題,消費者負責訂閱主題并進行消費。
- partition 是 topic 的物理概念,每個 topic 可以細分為多個 partition,每個 partition 只屬于單個 topic,并且包含不同的消息,partition 用于提高 topic 的存儲和消費的性能和可擴展性,可以將 topic 分散在多個 broker 上,并支持多個 consumer 并行消費。
- offset 是 partition 中每條消息的唯一標識,是一個單調(diào)遞增且不變的值,由 kafka 自動維護,offset 用于定位和記錄消息在 partition 中的位置和消費進度,保證 partition 內(nèi)的消息有序。
本文將給大家介紹 offset 的相關(guān)概念,大綱如下:
- offset 的作用和意義
- offset 的存儲和管理
- offset 的提交和重置
- offset 的消費和保證
offset 的作用和意義
offset 是 Kafka 為每條消息分配的一個唯一的編號,它表示消息在分區(qū)中的順序位置。offset 是從 0 開始的,每當有新的消息寫入分區(qū)時,offset 就會加 1。offset 是不可變的,即使消息被刪除或過期,offset 也不會改變或重用。
offset 的作用主要有兩個:
- 一是用來定位消息。通過指定 offset,消費者可以準確地找到分區(qū)中的某條消息,或者從某個位置開始消費消息。
- 二是用來記錄消費進度。消費者在消費完一條消息后,需要提交 offset 來告訴 Kafka broker 自己消費到哪里了。這樣,如果消費者發(fā)生故障或重啟,它可以根據(jù)保存的 offset 來恢復(fù)消費狀態(tài)。
offset 的存儲和管理
offset 的存儲和管理主要涉及到兩個方面:生產(chǎn)者端和消費者端。
生產(chǎn)者端
生產(chǎn)者在向 Kafka 發(fā)送消息時,可以指定一個分區(qū)鍵(Partition Key),Kafka 會根據(jù)這個鍵和分區(qū)算法來決定消息應(yīng)該發(fā)送到哪個分區(qū)。如果沒有指定分區(qū)鍵,Kafka 會采用輪詢或隨機的方式來選擇分區(qū)。生產(chǎn)者也可以自定義分區(qū)算法。
當消息被寫入到分區(qū)后,Kafka broker 會為消息分配一個 offset,并返回給生產(chǎn)者。生產(chǎn)者可以根據(jù)返回的 offset 來確認消息是否成功寫入,并進行重試或其他處理。
消費者端
消費者在消費 Kafka 消息時,需要維護一個當前消費的 offset 值,以及一個已提交的 offset 值。當前消費的 offset 值表示消費者正在消費的消息的位置,已提交的 offset 值表示消費者已經(jīng)確認消費過的消息的位置。
消費者在消費完一條消息后,需要提交 offset 來更新已提交的 offset 值。提交 offset 的方式有兩種:自動提交和手動提交。
- 自動提交:Kafka 提供了一個配置參數(shù) enable.auto.commit,默認為 true,表示開啟自動提交功能。自動提交功能會在后臺定期(由 auto.commit.interval.ms 參數(shù)控制)將當前消費的 offset 值提交給 Kafka broker。
- 手動提交:如果 enable.auto.commit 設(shè)置為 false,則表示關(guān)閉自動提交功能,此時消費者需要手動調(diào)用 commitSync 或 commitAsync 方法來提交 offset。手動提交功能可以讓消費者更靈活地控制何時以及如何提交 offset。
無論是自動提交還是手動提交,offset 的實際存儲位置都是在 Kafka 的一個內(nèi)置主題中:__consumer_offsets。這個主題有 50 個分區(qū)(可配置),每個分區(qū)存儲一部分消費組(Consumer Group)的 offset 信息。Kafka broker 會根據(jù)消費組 ID 和主題名來計算出一個哈希值,并將其映射到 __consumer_offsets 主題的某個分區(qū)上。
__consumer_offsets 主題是 Kafka 0.9.0 版本引入的新特性,之前的版本是將 offset 存儲在 Zookeeper 中。但是 Zookeeper 不適合大量寫入,因此后來改為存儲在 Kafka 自身中,提高了性能和可靠性。
offset 的提交和重置
提交 offset 是消費者在消費完一條消息后,將當前消費的 offset 值更新到 Kafka broker 中的操作。提交 offset 的目的是為了記錄消費進度,以便在消費者發(fā)生故障或重啟時,能夠從上次消費的位置繼續(xù)消費。
重置 offset 是消費者在啟動或運行過程中,將當前消費的 offset 值修改為其他值的操作。重置 offset 的目的是為了調(diào)整消費位置,以便在需要重新消費或跳過某些消息時,能夠?qū)崿F(xiàn)這個需求。
提交 offset
提交 offset 的方式有兩種:自動提交和手動提交。前面已經(jīng)介紹過這兩種方式的區(qū)別和用法,這里不再贅述。需要注意的是,無論是自動提交還是手動提交,都不保證提交成功。因為 Kafka broker 可能發(fā)生故障或網(wǎng)絡(luò)延遲,導(dǎo)致提交失敗或延遲。因此,消費者需要處理提交失敗或延遲的情況。
- 提交失?。喝绻峤皇?,消費者可以選擇重試或放棄。重試的話,可能會導(dǎo)致多次提交同一個 offset 值,但是不會影響正確性,因為 Kafka broker 會忽略重復(fù)的 offset 值。放棄的話,可能會導(dǎo)致下次啟動時重新消費已經(jīng)消費過的消息,但是不會影響完整性,因為 Kafka 消息是冪等的。
- 提交延遲:如果提交延遲,消費者可以選擇等待或繼續(xù)。等待的話,可能會導(dǎo)致消費速度變慢,或者超過 session.timeout.ms 參數(shù)設(shè)置的時間而被認為已經(jīng)死亡。繼續(xù)的話,可能會導(dǎo)致下次啟動時漏掉一些沒有提交成功的消息。
重置 offset
重置 offset 的方式有兩種:手動重置和自動重置。手動重置是指消費者主動調(diào)用 seek 或 seekToBeginning 或 seekToEnd 方法來修改當前消費的 offset 值。自動重置是指消費者在啟動時根據(jù) auto.offset.reset 參數(shù)來決定從哪個位置開始消費。
- 手動重置:手動重置可以讓消費者精確地控制從哪個位置開始消費。例如,如果想要重新消費某個分區(qū)的所有消息,可以調(diào)用 seekToBeginning 方法將 offset 設(shè)置為 0;如果想要跳過某個分區(qū)的所有消息,可以調(diào)用 seekToEnd 方法將 offset 設(shè)置為最大值;如果想要從某個具體的位置開始消費,可以調(diào)用 seek 方法將 offset 設(shè)置為任意值。
- 自動重置:自動重置可以讓消費者在啟動時根據(jù) auto.offset.reset 參數(shù)來決定從哪個位置開始消費。auto.offset.reset 參數(shù)有三個可選值:earliest, latest 和 none。earliest 表示從最早的可用消息開始消費;latest 表示從最新的可用消息開始消費;none 表示如果沒有可用的 offset,則拋出異常。
offset 的消費和保證
offset 的消費和保證主要涉及到兩個方面:順序性和一致性。
順序性
順序性是指 Kafka 消息是否按照發(fā)送和接收的順序進行處理。Kafka 只保證分區(qū)內(nèi)的順序性,即同一個分區(qū)內(nèi)的消息按照 offset 的順序進行發(fā)送和接收。但是不保證主題內(nèi)或跨主題的順序性,即不同分區(qū)內(nèi)的消息可能會亂序發(fā)送和接收。因此,如果需要保證主題內(nèi)或跨主題的順序性,需要在生產(chǎn)者和消費者端進行額外的處理,例如使用同一個分區(qū)鍵或同一個消費組。
一致性
一致性是指 Kafka 消息是否能夠被正確地發(fā)送和接收,不會出現(xiàn)丟失或重復(fù)的情況。Kafka 提供了三種不同級別的一致性保證:最多一次(At most once),最少一次(At least once)和精確一次(Exactly once)。
- 最多一次:最多一次是指 Kafka 消息只會被發(fā)送或接收一次或零次,不會出現(xiàn)重復(fù)的情況,但是可能會出現(xiàn)丟失的情況。這種保證的實現(xiàn)方式是在生產(chǎn)者端關(guān)閉重試功能,在消費者端在消費消息之前提交 offset。這種保證適用于對消息丟失不敏感的場景,例如日志收集或監(jiān)控。
- 最少一次:最少一次是指 Kafka 消息只會被發(fā)送或接收一次或多次,不會出現(xiàn)丟失的情況,但是可能會出現(xiàn)重復(fù)的情況。這種保證的實現(xiàn)方式是在生產(chǎn)者端開啟重試功能,在消費者端在消費消息之后提交 offset。這種保證適用于對消息重復(fù)不敏感的場景,例如計數(shù)或累加。
- 精確一次:精確一次是指 Kafka 消息只會被發(fā)送或接收一次,不會出現(xiàn)丟失或重復(fù)的情況。這種保證的實現(xiàn)方式是在生產(chǎn)者端和消費者端使用事務(wù)功能,在消費者端使用冪等功能。這種保證適用于對消息丟失和重復(fù)都敏感的場景,例如轉(zhuǎn)賬或支付。