了解消息代理。 學習使用 ActiveMQ 和 Kafka 進行消息傳遞的機制。 第 3 章卡夫卡

續小書的翻譯:
了解消息代理
作者:Jakub Korab,出版商:O'Reilly Media, Inc.,出版日期:2017 年 9781492049296 月,ISBN:XNUMX。

上一個翻譯部分: 了解消息代理。 學習使用 ActiveMQ 和 Kafka 進行消息傳遞的機制。 第一章簡介

第3章

卡夫卡

Kafka 由 LinkedIn 開發,旨在解決傳統消息代理的一些局限性,避免必須為不同的點對點交互設置多個消息代理,這在本書第 28 頁的“向上和向外擴展”下進行了描述. 用例 LinkedIn 在很大程度上依賴於單向攝取大量數據,例如頁麵點擊和訪問日誌,同時仍然允許多個系統使用這些數據,而不會影響生產者或其他消費者的生產力。 事實上,Kafka 存在的原因是為了獲得通用數據管道描述的那種消息傳遞架構。

鑑於此最終目標,自然會出現其他要求。 卡夫卡應該:

  • 速度極快
  • 處理消息時提供更多帶寬
  • 支持發布者-訂閱者和點對點模型
  • 不要因為增加消費者而放慢速度。 例如,隨著目的地消費者數量的增加,ActiveMQ 中隊列和主題的性能都會下降。
  • 可橫向擴展; 如果一個持久化消息的代理只能以最大磁盤速度這樣做,那麼超越單個代理實例以提高性能是有意義的
  • 限制對存儲和重新檢索消息的訪問

為了實現這一切,Kafka 採用了一種重新定義客戶端和消息代理的角色和職責的架構。 JMS 模型非常面向代理,代理負責分發消息,而客戶端只需擔心發送和接收消息。 另一方面,Kafka 是以客戶端為中心的,客戶端具有傳統代理的許多功能,例如向消費者公平分發相關消息,以換取極其快速和可擴展的代理。 對於使用過傳統消息系統的人來說,使用 Kafka 需要從根本上改變想法。
這一工程方嚮導致了消息傳遞基礎設施的創建,與傳統代理相比,該基礎設施能夠將吞吐量提高多個數量級。 正如我們將看到的,這種方法需要權衡取捨,這意味著 Kafka 不適合某些類型的工作負載和已安裝的軟件。

統一目的地模型

為了滿足上述要求,Kafka 在一種目的地下結合了發布-訂閱和點對點消息傳遞 - 話題. 這讓使用過消息系統的人感到困惑,其中“主題”一詞指的是一種廣播機制,從中(從主題)閱讀是非持久的。 正如本書簡介中所定義的,Kafka 主題應該被視為一種混合目的地類型。

對於本章的其餘部分,除非我們另有明確說明,否則術語“主題”將指代 Kafka 主題。

要充分了解主題的行為方式以及它們提供的保證,我們需要首先了解它們在 Kafka 中的實現方式。
Kafka 中的每個主題都有自己的日誌。
向 Kafka 發送消息的生產者寫入此日誌,消費者使用不斷向前移動的指針從日誌中讀取。 Kafka 會定期刪除日誌中最舊的部分,無論這些部分中的消息是否已被讀取。 Kafka 設計的核心部分是代理不關心消息是否被讀取——這是客戶的責任。

術語“log”和“pointer”沒有出現在 卡夫卡文檔. 此處使用這些眾所周知的術語來幫助理解。

這種模型與ActiveMQ完全不同,ActiveMQ將來自所有隊列的消息存儲在同一個日誌中,broker在讀取消息後將消息標記為已刪除。
現在讓我們更深入地挖掘並更詳細地查看主題日誌。
Kafka 日誌由幾個分區組成(圖3-1). Kafka 保證每個分區嚴格排序。 這意味著以特定順序寫入分區的消息將以相同的順序讀取。 每個分區都實現為一個滾動日誌文件,其中包含 子集 其生產者發送到主題的所有消息的(子集)。 默認情況下,創建的主題包含一個分區。 分區的思想是Kafka進行水平擴展的中心思想。

了解消息代理。 學習使用 ActiveMQ 和 Kafka 進行消息傳遞的機制。 第 3 章卡夫卡
圖 3-1。 卡夫卡分區

當生產者向 Kafka 主題發送消息時,它決定將消息發送到哪個分區。 稍後我們將對此進行更詳細的介紹。

閱讀信息

想要讀取消息的客戶端管理一個名為 消費者群體,它指向 抵消 分區中的消息。 偏移量是從分區開始處的 0 開始的增量位置。 通過用戶定義的 group_id 在 API 中引用的這個消費者組對應於 一個邏輯消費者或系統.

大多數消息傳遞系統使用多個實例和線程從目標讀取數據以並行處理消息。 因此,通常會有許多消費者實例共享同一個消費者組。

讀取問題可以表示為:

  • 主題有多個分區
  • 多組消費者可以同時使用一個topic
  • 一組消費者可以有多個獨立的實例

這是一個不平凡的多對多問題。 為了理解 Kafka 如何處理消費者組、消費者實例和分區之間的關係,讓我們來看一系列逐漸復雜的讀取場景。

消費者和消費者群體

讓我們以一個具有一個分區的主題作為起點(圖3-2).

了解消息代理。 學習使用 ActiveMQ 和 Kafka 進行消息傳遞的機制。 第 3 章卡夫卡
圖 3-2。 消費者從分區讀取

當消費者實例使用自己的 group_id 連接到該主題時,它會被分配一個讀取分區和該分區中的偏移量。 此偏移量的位置可在客戶端中配置為指向最近位置(最新消息)或最早位置(最舊消息)的指針。 消費者從主題中請求(輪詢)消息,這導致它們從日誌中順序讀取。
偏移位置定期提交回 Kafka 並作為消息存儲在內部主題中 _consumer_offsets. 與常規代理不同,已讀消息仍未刪除,客戶端可以倒回偏移量以重新處理已查看的消息。

當第二個邏輯消費者使用不同的 group_id 連接時,它管理獨立於第一個的第二個指針(圖3-3). 因此,Kafka 主題就像一個隊列,其中有一個消費者,就像一個普通的發布-訂閱 (pub-sub) 主題,多個消費者訂閱,還有一個額外的好處,即所有消息都被存儲並且可以被多次處理。

了解消息代理。 學習使用 ActiveMQ 和 Kafka 進行消息傳遞的機制。 第 3 章卡夫卡
圖 3-3。 不同消費者組中的兩個消費者從同一個分區讀取

消費者組中的消費者

當一個消費者實例從分區讀取數據時,它可以完全控制指針並處理消息,如上一節所述。
如果消費者的多個實例使用相同的 group_id 連接到具有一個分區的主題,那麼最後連接的實例將獲得指針的控制權,並且從那一刻起它將接收所有消息(圖3-4).

了解消息代理。 學習使用 ActiveMQ 和 Kafka 進行消息傳遞的機制。 第 3 章卡夫卡
圖 3-4。 同一個消費者組中的兩個消費者從同一個分區讀取

這種消費者實例數超過分區數的處理方式,可以認為是一種獨占消費者。 如果您需要消費者實例的“主動-被動”(或“熱-暖”)集群,這可能很有用,儘管並行運行多個消費者(“主動-主動”或“熱-熱”)比消費者。待命。

與普通 JMS 隊列的行為方式相比,上述消息分發行為可能令人驚訝。 在這個模型中,發送到隊列的消息將在兩個消費者之間平均分配。

大多數情況下,當我們創建多個消費者實例時,我們這樣做要么是為了並行處理消息,要么是為了提高讀取速度,要么是為了增加讀取過程的穩定性。 由於一次只有一個消費者實例可以從一個分區中讀取數據,那麼這在 Kafka 中是如何實現的呢?

一種方法是使用單個消費者實例讀取所有消息並將它們傳遞給線程池。 雖然這種方法增加了處理吞吐量,但它增加了消費者邏輯的複雜性並且對增加讀取系統的健壯性沒有任何作用。 如果消費者的一個副本由於電源故障或類似事件而宕機,則減法停止。

在 Kafka 中解決這個問題的規範方法是使用 bО更多的分區。

分區

分區是並行讀取和擴展主題超出單個代理實例帶寬的主要機制。 為了更好地理解這一點,讓我們考慮一種情況,其中有一個主題有兩個分區並且一個消費者訂閱了這個主題(圖3-5).

了解消息代理。 學習使用 ActiveMQ 和 Kafka 進行消息傳遞的機制。 第 3 章卡夫卡
圖 3-5。 一個消費者從多個分區讀取

在這種情況下,消費者可以控制兩個分區中與其 group_id 對應的指針,並開始從兩個分區讀取消息。
當將同一 group_id 的另一個消費者添加到該主題時,Kafka 將其中一個分區從第一個消費者重新分配給第二個消費者。 之後,消費者的每個實例將從主題的一個分區中讀取(圖3-6).

要保證消息在 20 個線程中並行處理,至少需要 20 個分區。 如果分區較少,您將只剩下無事可做的消費者,正如前面討論獨占消費者時所描述的那樣。

了解消息代理。 學習使用 ActiveMQ 和 Kafka 進行消息傳遞的機制。 第 3 章卡夫卡
圖 3-6。 同一個消費者組中的兩個消費者從不同的分區讀取

這種方案相比維護JMS隊列所需的消息分發,大大降低了Kafka broker的複雜度。 在這裡您無需擔心以下幾點:

  • 根據循環分配、預取緩衝區的當前容量或先前的消息(對於 JMS 消息組),哪個消費者應該接收下一條消息。
  • 哪些消息被發送給哪些消費者,以及在失敗的情況下是否應該重新傳遞它們。

Kafka 代理要做的就是在消費者請求時按順序將消息傳遞給消費者。

然而,並行校對和重新發送失敗消息的要求並沒有消失——它們的責任只是從代理轉移到客戶端。 這意味著您的代碼中必須考慮到它們。

發送信息

該消息的生產者有責任決定將消息發送到哪個分區。 要了解完成此操作的機制,我們首先需要考慮我們實際發送的到底是什麼。

在 JMS 中,我們使用帶有元數據(標頭和屬性)的消息結構和包含有效負載(有效負載)的主體,而在 Kafka 中,消息是 對“鍵值”. 消息負載作為值發送。 另一方面,密鑰主要用於分區並且必須包含 業務邏輯特定鍵將相關消息放在同一分區中。

在第 2 章中,我們討論了需要由單個消費者按順序處理相關事件的在線投注場景:

  1. 用戶帳戶已配置。
  2. 錢記入帳戶。
  3. 從賬戶中提取資金的賭注。

如果每個事件都是發佈到主題的消息,那麼自然鍵就是帳戶 ID。
當使用 Kafka Producer API 發送消息時,它會被傳遞給一個分區函數,根據消息和 Kafka 集群的當前狀態,該函數返回消息應該發送到的分區的 ID。 此功能是通過 Partitioner 接口在 Java 中實現的。

這個界面看起來像這樣:

interface Partitioner {
    int partition(String topic,
        Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster);
}

Partitioner 實現對鍵使用默認的通用哈希算法來確定分區,如果沒有指定鍵則使用循環法。 在大多數情況下,此默認值效果很好。 但是,將來您會想要自己編寫。

編寫自己的分區策略

讓我們看一個示例,您希望在其中發送元數據以及消息有效負載。 我們示例中的有效載荷是向遊戲帳戶存款的指令。 指令是我們希望保證在傳輸時不被修改的東西,並且希望確保只有受信任的上游系統才能啟動該指令。 在這種情況下,發送和接收系統同意使用簽名來驗證消息。
在普通的 JMS 中,我們簡單地定義一個“消息簽名”屬性並將其添加到消息中。 但是Kafka並沒有給我們提供傳遞元數據的機制,只有一個key和一個value。

由於該值是我們要保留其完整性的銀行轉賬有效負載,因此我們別無選擇,只能定義要在密鑰中使用的數據結構。 假設我們需要一個賬戶 ID 來進行分區,因為所有與賬戶相關的消息都必須按順序處理,所以我們會得到以下 JSON 結構:

{
  "signature": "541661622185851c248b41bf0cea7ad0",
  "accountId": "10007865234"
}

因為簽名的值會根據有效負載而變化,所以 Partitioner 接口的默認哈希策略不會可靠地對相關消息進行分組。 因此,我們需要編寫自己的策略來解析此鍵並對 accountId 值進行分區。

Kafka 包括校驗和以檢測存儲中消息的損壞,並具有全套安全功能。 即便如此,有時也會出現行業特定的要求,例如上述要求。

用戶的分區策略必須確保所有相關消息最終都在同一個分區中。 雖然這看起來很簡單,但由於排序相關消息的重要性以及主題中分區數量的固定程度,要求可能會變得複雜。

一個主題中的分區數量會隨著時間的推移而變化,因為如果流量超出最初的預期,它們可能會被添加。 因此,消息鍵可以與它們最初發送到的分區相關聯,這意味著在生產者實例之間共享一個狀態。

另一個需要考慮的因素是跨分區的消息均勻分佈。 通常,密鑰不會在消息中均勻分佈,並且哈希函數不能保證一小部分密鑰的消息公平分佈。
請務必注意,無論您選擇如何拆分消息,分隔符本身都可能需要重複使用。

考慮在不同地理位置的 Kafka 集群之間複製數據的需求。 為此,Kafka 附帶了一個名為 MirrorMaker 的命令行工具,用於從一個集群讀取消息並將它們傳輸到另一個集群。

MirrorMaker 必須了解複製主題的鍵,以便在集群之間複製時保持消息之間的相對順序,因為該主題的分區數在兩個集群中可能不同。

自定義分區策略相對較少,因為默認哈希或循環法在大多數情況下效果很好。 但是,如果您需要強順序保證或需要從有效負載中提取元數據,那麼您應該仔細研究分區。

Kafka 的可擴展性和性能優勢來自於將傳統代理的一些責任轉移到客戶端。 在這種情況下,決定在並行工作的多個消費者之間分發可能相關的消息。

JMS 代理也需要處理這樣的要求。 有趣的是,通過 JMS 消息組(粘性負載平衡 (SLB) 策略的變體)實現的向同一消費者發送相關消息的機制也需要發送方將消息標記為相關。 在 JMS 的情況下,代理負責將這組相關消息發送給眾多消費者中的一個,並在消費者脫落時轉移該組的所有權。

生產商協議

發送消息時,分區並不是唯一要考慮的事情。 我們來看看Java API中Producer類的send()方法:

Future < RecordMetadata > send(ProducerRecord < K, V > record);
Future < RecordMetadata > send(ProducerRecord < K, V > record, Callback callback);

需要立即註意的是,這兩個方法都返回了 Future,這表明發送操作不是立即執行的。 結果是一條消息 (ProducerRecord) 被寫入每個活動分區的發送緩衝區,並作為 Kafka 客戶端庫中的後台線程發送到代理。 雖然這使事情變得非常快,但這意味著如果進程停止,沒有經驗的應用程序可能會丟失消息。

與往常一樣,有一種方法可以以性能為代價使發送操作更可靠。 這個緩衝區的大小可以設置為0,發送應用程序線程將被強制等待,直到消息傳輸到broker完成,如下:

RecordMetadata metadata = producer.send(record).get();

有關閱讀消息的更多信息

閱讀消息具有額外的複雜性,需要進行推測。 與可以運行消息偵聽器以響應消息的 JMS API 不同, 消費者 卡夫卡只輪詢。 讓我們仔細看看這個方法 輪詢()用於此目的:

ConsumerRecords < K, V > poll(long timeout);

該方法的返回值是一個包含多個對象的容器結構 消費記錄 來自可能的幾個分區。 消費記錄 本身是具有關聯元數據的鍵值對的持有者對象,例如派生它的分區。

正如第 2 章所討論的,我們必須牢記消息在成功或未成功處理後會發生什麼,例如,如果客戶端無法處理消息或中止消息。 在 JMS 中,這是通過確認模式處理的。 代理將刪除成功處理的消息,或者重新傳遞原始或偽造的消息(假設使用了事務)。
卡夫卡的工作方式非常不同。 消息在校對後不會在代理中刪除,失敗時發生的情況是校對代碼本身的責任。

正如我們所說,消費者組與日誌中的偏移量相關聯。 與此偏移量關聯的日誌位置對應於要響應的下一條消息 輪詢(). 這個偏移量增加的時間點對於讀取是決定性的。

回到前面討論的閱讀模型,消息處理包括三個階段:

  1. 檢索消息以供閱讀。
  2. 處理消息。
  3. 確認消息。

Kafka 消費者自帶一個配置選項 啟用.auto.commit. 這是一個經常使用的默認設置,與包含單詞“auto”的設置一樣常見。

在 Kafka 0.10 之前,使用此選項的客戶端將發送在下一次調用時讀取的最後一條消息的偏移量 輪詢() 加工後。 這意味著如果客戶端已經處理過任何已獲取的消息但在調用之前意外銷毀,則可以重新處理這些消息 輪詢(). 因為代理不會保留任何關於一條消息被閱讀了多少次的狀態,所以下一個檢索該消息的消費者不會知道發生了什麼不好的事情。 這種行為是偽事務性的。 僅當消息被成功處理時才提交偏移量,但如果客戶端中止,代理將再次向另一個客戶端發送相同的消息。 此行為與消息傳遞保證一致”至少一次“。

在 Kafka 0.10 中,客戶端代碼已更改,以便根據配置由客戶端庫定期觸發提交 自動提交間隔.ms. 此行為介於 JMS AUTO_ACKNOWLEDGE 和 DUPS_OK_ACKNOWLEDGE 模式之間。 使用自動提交時,無論是否實際處理消息都可以提交消息——這可能發生在消費者速度較慢的情況下。 如果消費者中止,消息將由下一個消費者獲取,從提交的位置開始,這可能導致錯過消息。 在這種情況下,Kafka 並沒有丟失消息,只是讀取代碼沒有處理它們。

此模式與 0.9 版本具有相同的承諾:可以處理消息,但如果失敗,可能不會提交偏移量,從而可能導致傳遞加倍。 執行時獲取的消息越多 輪詢(),這個問題越多。

正如第 21 頁的“從隊列中讀取消息”中所討論的,在考慮故障模式的情況下,在消息傳遞系統中不存在一次性傳遞消息這樣的事情。

在Kafka中,提交(commit)一個偏移量(offset)有兩種方式:自動和手動。 在這兩種情況下,如果消息已處理但在提交之前失敗,則可以多次處理消息。 如果提交發生在後台並且您的代碼在處理之前完成(可能在 Kafka 0.9 和更早版本中),您也可以選擇根本不處理消息。

可以在Kafka consumer API中通過設置參數來控製手動offset commit過程 啟用.auto.commit 為 false 並顯式調用以下方法之一:

void commitSync();
void commitAsync();

如果您想“至少處理一次”消息,則必須手動提交偏移量 提交同步()通過在處理消息後立即執行此命令。

這些方法不允許消息在處理之前得到確認,但它們沒有採取任何措施來消除潛在的處理延遲,同時提供事務性的外觀。 Kafka 中沒有事務。 客戶端無法執行以下操作:

  • 自動回滾偽造的消息。 消費者自己必須處理由有問題的有效負載和後端中斷引起的異常,因為他們不能依賴代理重新傳遞消息。
  • 在一個原子操作中將消息發送到多個主題。 正如我們將很快看到的,對不同主題和分區的控制可以駐留在 Kafka 集群中的不同機器上,這些機器在發送時不協調事務。 在撰寫本文時,已經完成了一些工作,使 KIP-98 成為可能。
  • 將閱讀來自一個主題的一條消息與向另一個主題發送另一條消息相關聯。 同樣,Kafka 的架構依賴於許多獨立的機器作為一條總線運行,並且沒有試圖隱藏這一點。 例如,沒有允許您鏈接的 API 組件 消費者 и 製片人 在交易中。 在 JMS 中,這是由對象提供的 會議從中創建 消息生產者 и 消息消費者.

如果我們不能依賴事務,我們如何提供更接近傳統消息系統提供的語義?

如果在消息被處理之前消費者的偏移量可能會增加,例如在消費者崩潰期間,那麼消費者無法知道其消費者組在分配分區時是否錯過了消息。 因此,一種策略是將偏移量倒回到之前的位置。 Kafka 消費者 API 為此提供了以下方法:

void seek(TopicPartition partition, long offset);
void seekToBeginning(Collection < TopicPartition > partitions);

方法 尋找() 可以與方法一起使用
offsetsForTimes(地圖時間戳搜索) 回到過去某個特定時間點的狀態。

隱含地,使用這種方法意味著很可能會再次讀取和處理一些以前處理過的消息。 為避免這種情況,我們可以使用第 4 章中描述的冪等讀取來跟踪以前查看過的消息並消除重複項。

或者,您的消費者代碼可以保持簡單,只要消息丟失或重複是可以接受的。 當我們考慮通常使用 Kafka 的用例(例如處理日誌事件、指標、點擊跟踪等)時,我們明白單個消息的丟失不太可能對周圍的應用程序產生重大影響。 在這種情況下,默認值是完全可以接受的。 另一方面,如果您的應用程序需要發送付款,您必須仔細處理每條消息。 這一切都取決於上下文。

個人觀察表明,隨著信息強度的增加,每條信息的價值都會降低。 當以聚合形式查看時,大消息往往很有價值。

高可用性

Kafka 的高可用性方法與 ActiveMQ 的方法非常不同。 Kafka 是圍繞橫向擴展集群設計的,其中所有代理實例同時接收和分發消息。

Kafka 集群由運行在不同服務器上的多個代理實例組成。 Kafka 被設計為在普通的獨立硬件上運行,其中每個節點都有自己的專用存儲。 不建議使用網絡附加存儲 (SAN),因為多個計算節點會爭用時間。Ыe 存儲間隔並產生衝突。

卡夫卡是 永遠在線 系統。 許多大型 Kafka 用戶從不關閉他們的集群,軟件總是通過順序重啟進行更新。 這是通過保證與以前版本的消息和代理之間交互的兼容性來實現的。

連接到服務器集群的代理 動物園管理員,它充當配置數據註冊表,用於協調每個代理的角色。 ZooKeeper 本身是一個分佈式系統,通過建立信息複製來提供高可用性 法定人數.

在基本情況下,主題在 Kafka 集群中創建,具有以下屬性:

  • 分區數。 如前所述,此處使用的確切值取決於所需的並行讀取級別。
  • 複製因子(factor)決定了集群中有多少代理實例應該包含這個分區的日誌。

使用 ZooKeepers 進行協調,Kafka 嘗試在集群中的代理之間公平地分配新分區。 這是由充當控制器的單個實例完成的。

在運行時 對於每個主題分區 控制者 為經紀人分配角色 領導者 (領導者,大師,主持人)和 追隨者 (追隨者、奴隸、下屬)。 代理作為該分區的領導者,負責接收生產者發送給它的所有消息並將消息分發給消費者。 當消息發送到主題分區時,它們將被複製到充當該分區的跟隨者的所有代理節點。 包含分區日誌的每個節點稱為 複製品. 經紀人可以充當某些分區的領導者和其他分區的追隨者。

包含領導者持有的所有消息的追隨者稱為 同步副本 (處於同步狀態的副本,同步副本)。 如果充當分區領導者的代理髮生故障,則該分區的任何最新或同步的代理都可以接管領導角色。 這是一個令人難以置信的可持續設計。

生產者配置的一部分是參數 確認,它決定了在應用程序線程繼續發送之前有多少副本必須確認(acknowledge)收到一條消息:0、1 或全部。 如果設置為 全部,那麼當接收到一條消息時,領導者將在收到來自主題設置定義的多個線索(包括它自己)的記錄的確認(確認)後立即向生產者發送確認 最小同步副本數 (默認 1)。 如果無法成功複製消息,則生產者將拋出應用程序異常(沒有足夠的副本追加後副本不足).

一個典型的配置創建一個主題,其複制因子為 3(每個分區 1 個領導者,2 個追隨者)和參數 最小同步副本數 設置為 2。在這種情況下,集群將允許管理主題分區的代理之一關閉而不影響客戶端應用程序。

這讓我們回到了熟悉的性能和可靠性之間的權衡。 複製的發生是以等待來自追隨者的確認(確認)的額外等待時間為代價的。 雖然,因為它是並行運行的,所以復製到至少三個節點與兩個節點具有相同的性能(忽略網絡帶寬使用的增加)。

通過使用這種複制方案,Kafka 巧妙地避免了將每條消息物理寫入磁盤的需要 同步(). 生產者發送的每條消息都將寫入分區日誌,但如第 2 章所述,寫入文件最初是在操作系統的緩衝區中完成的。 如果這條消息被複製到另一個 Kafka 實例並在它的內存中,領導者的丟失並不意味著消息本身丟失了——它可以被一個同步的副本接管。
拒絕執行操作 同步() 意味著 Kafka 接收消息的速度與將消息寫入內存的速度一樣快。 相反,避免將內存刷新到磁盤的時間越長越好。 因此,為 Kafka 代理分配 64 GB 或更多內存的情況並不少見。 這種內存使用意味著單個 Kafka 實例可以輕鬆地以比傳統消息代理快數千倍的速度運行。

Kafka 也可以配置為應用操作 同步() 消息包。 由於 Kafka 中的所有內容都是面向包的,因此它實際上適用於許多用例,並且對於需要非常強大的保證的用戶來說是一個有用的工具。 Kafka 的許多純粹性能來自於作為數據包發送到代理的消息,並且這些消息是使用順序塊從代理中讀取的 零拷貝 操作(不執行將數據從一個內存區域複製到另一個內存區域的操作)。 後者是一個很大的性能和資源增益,只有通過使用定義分區方案的底層日誌數據結構才有可能。

與單個 Kafka 代理相比,Kafka 集群中的性能可能要好得多,因為主題分區可以橫向擴展到許多單獨的機器上。

結果

在本章中,我們了解了 Kafka 架構如何重新構想客戶端和代理之間的關係,以提供極其強大的消息傳遞管道,其吞吐量比傳統消息代理高出許多倍。 我們已經討論了它用於實現此目的的功能,並簡要介紹了提供此功能的應用程序的體系結構。 在下一章中,我們將研究基於消息傳遞的應用程序需要解決的常見問題,並討論處理這些問題的策略。 我們將在本章結尾概述如何一般地討論消息傳遞技術,以便您可以評估它們對您的用例的適用性。

上一個翻譯部分: 了解消息代理。 學習使用 ActiveMQ 和 Kafka 進行消息傳遞的機制。 第1章

翻譯完成: tele.gg/middle_java

待續...

只有註冊用戶才能參與調查。 登入, 請。

您的組織使用 Kafka 嗎?

  • Да

  • 沒有

  • 以前用過,現在不用

  • 我們打算用

38 位用戶投票。 8 名用戶棄權。

來源: www.habr.com

添加評論