Categories
程式開發

系統解讀Kafka的流和表(四):彈性和容錯能力


在上一篇文章中,我們了解了Kafka的處理層,以及Kafka Streams和ksqlDB的分佈式處理架構。在這篇文章中,我們將再次探討處理層,並深入理解Kafka是如何實現彈性伸縮和容錯能力的。

我們先從流和表的處理容錯能力開始,然後再介紹彈性。我們將會看到,它們實際上是一枚硬幣的兩面。

容錯處理

流和表具有容錯能力,因為它們的數據被可靠地存儲在Kafka中。對於流來說,這個相對好理解,因為流是直接與主題對應起來的,如果在處理過程中出了問題,重新讀取主題的數據就可以了。

這對於表來說就相對複雜了,因為表必須維護額外的信息,也就是它們的狀態,這樣才能進行有狀態的操作,比如COUNT()或SUM()。在Kafka Streams應用程序或ksqlDB服務器中,為了確保在保持高性能的同時實現有狀態處理,表需要被物化到本地磁盤。但是,機器或容器會宕機,本地保存的數據也會隨之丟失,那麼我們該如何確保表的容錯能力呢?

系統解讀Kafka的流和表(四):彈性和容錯能力 1

圖1. 表和狀態被物化到本地磁盤

存儲在表中的數據也被存儲在遠程的Kafka中。每張表都有自己的變更流,我們可以把它看成是一種內置的CDC。假設我們有一張客戶賬戶表,每次更新賬戶的餘額時,都會有一個對應的變更事件被添加到這張表所對應的變更流中。

與關係型數據庫的重做日誌類似,變更流就是表的事實來源。變更流持續不斷地被保存到Kafka主題中,所以這個主題也被叫作變更日誌主題。所以,表的容錯能力利用了流和表的二元性。在stream任務或運行任務的容器/虛擬機/機器發生故障時,表的數據可以通過變更流來恢復,數據的處理也因此不會被中斷,不會有數據丟失或產生錯誤的處理結果。

如果一個容器發生故障,那麼就需要在另一個容器上重建賬戶表,這樣就不需要重新運行整個處理過程。我們可以直接從變更日誌主題恢復表的狀態。變更日誌主題經過壓縮,所以整個恢復過程非常快,稍後我們將會看到。

系統解讀Kafka的流和表(四):彈性和容錯能力 2

圖2. 運行在機器A上的一個任務。如果機器發生宕機,任務會被遷移到另一台機器上。在新機器上,表的狀態被恢復到發生故障時的那個時刻,恢復完成之後,任務繼續執行。

彈性處理和伸縮性

彈性與上一小節講到的容錯能力有關。分佈式系統處理故障(比如容器崩潰)所需要做的與實現彈性(例如,通過增加容器或移除容器實現應用程序的伸縮)所需要做的實際上很相似。至於容器是因為有意被移除還是因為無意發生故障,這個並不重要。換句話說,彈性和容錯能力是一枚硬幣的兩面!

假設我們有兩個Kafka Streams應用程序實例。輸入數據是一個Kafka主題,這個主題有4個分區,那麼就會有4個stream任務。這4個任務被均勻地分配給兩個應用程序實例。如果現在加入第三個和第四個應用程序實例,那麼之前的任務及其表分區的一部分會被遷移到新的應用程序實例上。

系統解讀Kafka的流和表(四):彈性和容錯能力 3

圖3. 在加入新的應用程序實例之前

處理邏輯(比如過濾、轉換、連接、聚合等)不需要進行遷移,因為每個應用程序實例都已經包含了這些東西。唯一要做的事情是快速遷移數據,不管是幾KB還是幾GB。如果我們把已有的應用程序實例移除,那麼就反過來:任務和表被遷移到仍然存活的實例上。

系統解讀Kafka的流和表(四):彈性和容錯能力 4

圖4. 在新增應用程序實例之後

上述的每一個遷移步驟都是自動進行的,極大減少了應用程序開發者和運維人員的負擔。另外,應用程序的彈性操作可以在運行時完成,而其他流式處理框架在進行彈性操作時需要完全停止應用程序,進行重新配置和重新提交處理作業。

表和主題的壓縮

一般來說,表底層的主題應該是壓縮的。但有一種情況例外,比如基於一個已有的Kafka主題創建ksqlDB表,對於這種情況,與主題相關的配置都會被保留下來。壓縮是Kafka的一個特性,確保Kafka對主題分區裡的每一個鍵保留最新的事件,如圖5所示。它會定時移除同一個鍵的舊事件(如圖5示例中,Alice之前訪問過的網站),以此來減少表的變更流所佔用的存儲空間。

系統解讀Kafka的流和表(四):彈性和容錯能力 5

圖5. 同一個鍵的舊事件被定期移除

那麼,壓縮有哪些好處?有了壓縮功能,我們可以在Kafka中永久地存儲表數據,而不會讓數據漫無邊際地增長。這對於引用型數據(比如客戶資料、產品目錄、賬戶餘額、維度表,等等)來說非常有好處。 Kafka Connect就使用壓縮主題來保存配置信息。

壓縮的第二個好處是減少了應用程序在發生再均衡時所需要的恢復時間,因為從Kafka代理傳輸給ksqlDB服務器或Kafka Streams應用程序的數據減少了,這同時也提高了彈性和故障處理能力。假設我們有一張包含一百萬用戶的表,每天會發生很多變更事件,到現在已經有4億個事件了。在啟用了壓縮功能之後,恢復用戶表就會快很多,因為只需要讀取最新的一百萬個事件,而不是所有的4億個事件。

所以說,壓縮是很有用的。但要注意的是,壓縮會清除表的歷史事件,例如圖5中被虛線框起來的部分。如果你需要所有的歷史事件,那麼可以考慮禁用壓縮功能。但請注意,對於流,不應該啟用壓縮功能,因為具有相同鍵的新事件不應該被認為是可以“取代”舊事件!

彈性和容錯能力的背後

在故障處理和彈性的背後實際上是Kafka的再均衡過程。在生產環境中運行Kafka Streams應用程序和ksqlDB服務器時,我們需要明白,有那麼一小段時間(通常很短),應用程序有一部分是不可用的,直到再均衡結束。在這一小段時間內,ksqlDB或Kafka Streams應用程序會對受影響的任務和表或者狀態進行遷移。

遷移任務涉及的數據越多,恢復所需的時間也就越長。如果需要傳輸的數據太多,那麼客戶端應用程序實例(保存表分區的地方)和服務器端的Kafka代理(包含主題分區,可以基於這些分區來恢復表的分區)之間的帶寬就會成為瓶頸。

之前提到的壓縮功能(默認是啟用的)在減少數據方面非常有效。另一個可用於縮短恢復時間的功能是待命副本(standby replica),這個選項是可選的,但在生產環境中建議開啟。

以Kafka Streams為例,應用程序實例可以被配置成其他實例的被動數據副本。在發生故障時,應用程序實例的任務被遷移到另一個已經包含了原有數據副本的實例上,這就極大地加快了恢復速度。不過,待命副本也有缺點,因為它增加了應用程序實例和Kafka代理之間的網絡通信,而對於應用程序來說,因為增加了額外的數據副本,本地存儲消費也隨之增加。

系統解讀Kafka的流和表(四):彈性和容錯能力 6

圖6. 待命副本默認是禁用的

系統解讀Kafka的流和表(四):彈性和容錯能力 7

圖7. 如果啟用了待命副本,當應用程序實例2發生宕機,應用程序實例1可以很快接管實例2的處理任務,因為它也具有所需的表數據

除了上述這些東西,Kafka社區還在嘗試其他一些改進,能夠更快更有效地實現Kafka的彈性和容錯能力。這些工作是Kafka 2.4和Confluent Platform 5.4的一部分,包括固定的消費者群組關係(為了減少因過度或不必要的再均衡導致的應用程序宕機時間)和增量式再均衡(提供更順暢的伸縮體驗,特別是如果應用程序是部署在雲端或Kubernetes上)。

最後,我想分享一個容量規劃技巧:在規劃本地數據存儲容量時,不要忘了考慮彈性和容錯能力需要額外的空間,因為stream任務及其相關的表分區可能會在Kafka Streams應用程序實例或ksqlDB服務器之間移動。如果預期的本地表數據為50GB,並且有5個應用程序實例,那麼每個應用程序只分配10GB空間是不夠的,如果這樣的話,應用程序就沒有辦法在其他實例發生故障時接管它們的工作。

分區和並行處理

Kafka的並行處理程度是由輸入數據的分區數決定的,不管是流、表還是主題。如果有20個輸入分區,那麼就會有20個stream任務。也就是說,你可以運行20個Kafka Streams應用程序實例(或者一個包含20個服務器節點的ksqlDB集群),然後這些任務均勻地分配給這些實例。其他多餘的應用程序實例將會空閒。

系統解讀Kafka的流和表(四):彈性和容錯能力 8

圖8. 並行處理度不會超過輸入分區的數量

如果你想要提高並行處理水平該怎麼辦?如果你需要更高的並行處理水平,那就增加流或表的分區數。但對於已有的應用程序來說,要格外小心,因為有些事件現在被發送給了不同的分區。如果只是某個場景需要更高的處理並行度,可以考慮讓原有的流或表保持不變,然後創建一新的具有更多分區的流或表。

這是ksqlDB的實例代碼:
https://gist.github.com/confluentgist/3980184d5b45eb564aa18a1ad8dda126

解決數據傾斜問題

在進行並行處理時,可能會遇到這種情況:有些stream任務需要處理的數據很多,有些則很少。我們通過監控相關的指標(例如消費延遲)就可以知道是否發生了這種情況。

系統解讀Kafka的流和表(四):彈性和容錯能力 9

圖9. Confluent Control Center的指標監控

下面列出了兩個常見的導致數據傾斜的原因及其解決辦法。

原因 解決方案
存儲傾斜:分配給分區的數據不均勻。有一小部分分區分配到的事件數量較多,這種分區叫作熱分區。 數據攝入:為生產者找到一個更好的分區函數,讓事件分佈得更均勻。存儲:對現有事件進行重分區,把它們放入具有更多分區的主題中。
處理傾斜:事件分佈是均勻的,但有些事件需要更多的處理時間。 進行垂直伸縮,比如使用更強大的CPU。

系統解讀Kafka的流和表(四):彈性和容錯能力 10

圖10. 數據傾斜可能會導致出現熱分區

總結

這是系列文章的最後一篇。在本系列文章中,我們先是介紹了基礎元素——事件、流和表,然後了解了Kafka的存儲層,然後是Kafka的處理層,還介紹了ksqlDB和Kafka Streams。最後,我們探討了這些應用程序的彈性和容錯能力是如何實現的。

原文鏈接:

https://www.confluent.io/blog/kafka-streams-tables-part-4-elasticity-fault-tolerance-advanced-concepts/

系列文章:

《系統解讀Kafka的流和表(一):開篇》

《系統解讀Kafka的流和表(二):主題、分區和存儲》

《系統解讀Kafka的流和表(三):處理層》