不僅僅是處理:我們如何從 Kafka Streams 建立分散式資料庫,以及它的結果

嘿哈布爾!

我們提醒您,遵循這本書 卡夫卡 我們出版了一本同樣有趣的關於圖書館的著作 卡夫卡流 API.

不僅僅是處理:我們如何從 Kafka Streams 建立分散式資料庫,以及它的結果

目前,社群剛剛了解這個強大工具的限制。 因此,最近發表了一篇文章,我們想向您介紹該文章的翻譯。 作者從自己的經驗講述如何將Kafka Streams變成分散式資料儲存。 享受閱讀!

阿帕契庫 卡夫卡流 在全球範圍內的企業中使用 Apache Kafka 進行分散式串流處理。 該框架未被充分重視的方面之一是它允許您儲存基於執行緒處理生成的本機狀態。

在本文中,我將告訴您我們公司在開發雲端應用程式安全產品時如何利用這個機會獲利。 使用 Kafka Streams,我們創建了共享狀態微服務,每個微服務都充當有關係統中物件狀態的可靠資訊的容錯且高度可用的來源。 對我們來說,這在可靠性和易於支援方面都向前邁出了一步。

如果您對允許您使用單一中央資料庫來支援物件的正式狀態的替代方法感興趣,請閱讀它,它會很有趣...

為什麼我們認為是時候改變共享狀態的工作方式了

我們需要根據代理程式報告維護各種物件的狀態(例如:網站是否受到攻擊)? 在遷移到 Kafka Streams 之前,我們經常依賴單一中央資料庫(+服務 API)進行狀態管理。 這種方法有其缺點: 日期密集的情況 保持一致性和同步成為一個真正的挑戰。 資料庫可能成為瓶頸或最終陷入困境 競爭條件 並遭受不可預測性的困擾。

不僅僅是處理:我們如何從 Kafka Streams 建立分散式資料庫,以及它的結果

圖 1:過渡到先前看到的典型分裂狀態場景
Kafka 和 Kafka Streams:代理程式透過 API 傳達其視圖,更新狀態透過中央資料庫計算

了解 Kafka Streams,輕鬆建立共享狀態微服務

大約一年前,我們決定認真研究我們的共享狀態場景以解決這些問題。 我們立即決定嘗試 Kafka Streams - 我們知道它的可擴展性、高可用性和容錯性,它具有豐富的串流功能(轉換,包括有狀態的轉換)。 這正是我們所需要的,更不用說 Kafka 中的訊息系統已經變得多麼成熟和可靠。

我們創建的每個有狀態微服務都建構在具有相當簡單拓撲的 Kafka Streams 實例之上。 它由 1) 來源 2) 具有持久鍵值儲存的處理器 3)​​ 接收器組成:

不僅僅是處理:我們如何從 Kafka Streams 建立分散式資料庫,以及它的結果

圖 2:有狀態微服務的流實例的預設拓樸。 請注意,這裡還有一個包含規劃元資料的儲存庫。

在這種新方法中,代理程式編寫訊息並饋入來源主題,而消費者(例如郵件通知服務)透過接收器(輸出主題)接收計算的共享狀態。

不僅僅是處理:我們如何從 Kafka Streams 建立分散式資料庫,以及它的結果

圖 3:共享微服務場景的新範例任務流程:1) 代理程式產生一條到達 Kafka 來源主題的訊息; 2) 具有共享狀態的微服務(使用 Kafka Streams)對其進行處理並將計算出的狀態寫入最終的 Kafka 主題; 之後3)消費者接受新狀態

嘿,這個內建的鍵/值存儲實際上非常有用!

如上所述,我們的共享狀態拓撲包含一個鍵值儲存。 我們找到了幾種使用它的選項,下面描述了其中兩個。

選項#1:使用鍵值儲存進行計算

我們的第一個鍵值儲存包含計算所需的輔助資料。 例如,在某些情況下,共享狀態是由「多數票」原則決定的。 儲存庫可以保存有關某個物件狀態的所有最新代理報告。 然後,當我們從一個代理或另一個代理收到新報告時,我們可以保存它,從儲存中檢索所有其他代理關於相同物件狀態的報告,然後重複計算。
下面的圖 4 顯示了我們如何將鍵/值儲存公開給處理器的處理方法,以便可以處理新訊息。

不僅僅是處理:我們如何從 Kafka Streams 建立分散式資料庫,以及它的結果

圖 4:我們為處理器的處理方法開放對鍵值儲存的存取(此後,每個使用共享狀態的腳本都必須實作該方法 doProcess)

選項#2:在 Kafka Streams 之上建立 CRUD API

建立了基本任務流程後,我們開始嘗試為共享狀態微服務編寫 RESTful CRUD API。 我們希望能夠檢索部分或所有物件的狀態,以及設定或刪除物件的狀態(對於後端支援有用)。

為了支援所有獲取狀態 API,每當我們在處理過程中需要重新計算狀態時,我們都會將其長期儲存在內建鍵值儲存中。 在這種情況下,使用 Kafka Streams 的單一實例實作這樣的 API 變得非常簡單,如下清單所示:

不僅僅是處理:我們如何從 Kafka Streams 建立分散式資料庫,以及它的結果

圖 5:使用內建鍵值儲存以取得物件的預計算狀態

透過 API 更新物件的狀態也很容易實現。 基本上,您需要做的就是建立一個 Kafka 生產者並使用它來建立包含新狀態的記錄。 這確保了透過 API 產生的所有訊息都將以與從其他生產者(例如代理)接收的訊息相同的方式進行處理。

不僅僅是處理:我們如何從 Kafka Streams 建立分散式資料庫,以及它的結果

圖 6:您可以使用 Kafka 生產者設定物件的狀態

小複雜:Kafka 有很多分區

接下來,我們希望透過為每個場景提供共用狀態微服務叢集來分配處理負載並提高可用性。 設定非常簡單:一旦我們將所有實例配置為在相同的應用程式 ID(以及相同的引導伺服器)下運行,幾乎所有其他操作都會自動完成。 我們還指定每個來源主題將由多個分區組成,以便可以為每個實例分配此類分區的子集。

我還將提到,製作狀態儲存的備份副本是常見的做法,以便在發生故障後恢復時將此副本傳輸到另一個執行個體。 對於 Kafka Streams 中的每個狀態存儲,都會使用更改日誌(追蹤本機更新)建立複製主題。 因此,Kafka 不斷備份狀態儲存。 因此,如果一個或另一個 Kafka Streams 實例發生故障,狀態儲存可以快速恢復到另一個實例上,相應的分區將儲存在該實例上。 我們的測試表明,即使儲存中有數百萬筆記錄,這也只需幾秒鐘即可完成。

從具有共享狀態的單一微服務遷移到微服務集群,實作 Get State API 變得不再那麼簡單。 在新情況下,每個微服務的狀態儲存僅包含整體情況的一部分(其鍵對應到特定分區的那些物件)。 我們必須確定哪個實例包含我們需要的物件的狀態,並且我們根據線程元資料來完成此操作,如下所示:

不僅僅是處理:我們如何從 Kafka Streams 建立分散式資料庫,以及它的結果

圖 7:使用流元數據,我們確定從哪個實例查詢所需物件的狀態; GET ALL API 使用了類似的方法

主要發現

Kafka Streams 中的狀態儲存可以充當事實上的分散式資料庫,

  • 在Kafka中不斷複製
  • CRUD API 可以輕鬆地建構在這樣的系統之上
  • 處理多個分區有點複雜
  • 也可以為串流拓撲新增一個或多個狀態儲存來儲存輔助資料。 此選項可用於:
  • 流處理過程中計算所需資料的長期存儲
  • 長期儲存數據,下次配置流實例時可能有用
  • 多得多...

這些和其他優點使 Kafka Streams 非常適合在像我們這樣的分散式系統中維護全域狀態。 事實證明,Kafka Streams 在生產中非常可靠(自從部署它以來,我們幾乎沒有遇到任何訊息遺失),我們相信它的功能將超越這一點!

來源: www.habr.com

添加評論