您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關Kafka的控制器controller如何理解,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
控制器組件(Controller),是 Apache Kafka 的核心組件。它的主要作用是在 Apache ZooKeeper 的幫助下管理和協調整個 Kafka 集群。集群中任意一臺 Broker 都能充當控制器的角色,但是,在運行過程中,只能有一個 Broker 成為控制器,行使其管理和協調的職責。換句話說,每個正常運轉的 Kafka 集群,在任意時刻都有且只有一個控制器。官網上有個名為 activeController 的 JMX 指標,可以幫助我們實時監控控制器的存活狀態。這個 JMX 指標非常關鍵,你在實際運維操作過程中,一定要實時查看這個指標的值。下面,我們就來詳細說說控制器的原理和內部運行機制。
在開始之前,我先簡單介紹一下 Apache ZooKeeper 框架。要知道,控制器是重度依賴 ZooKeeper 的,因此,我們有必要花一些時間學習下 ZooKeeper 是做什么的。Apache ZooKeeper 是一個提供高可靠性的分布式協調服務框架。它使用的數據模型類似于文件系統的樹形結構,根目錄也是以“/”開始。該結構上的每個節點被稱為 znode,用來保存一些元數據協調信息。如果以 znode 持久性來劃分,znode 可分為持久性 znode 和臨時 znode。持久性 znode 不會因為 ZooKeeper 集群重啟而消失,而臨時 znode 則與創建該 znode 的 ZooKeeper 會話綁定,一旦會話結束,該節點會被自動刪除。
ZooKeeper 賦予客戶端監控 znode 變更的能力,即所謂的 Watch 通知功能。一旦 znode 節點被創建、刪除,子節點數量發生變化,抑或是 znode 所存的數據本身變更,ZooKeeper 會通過節點變更監聽器 (ChangeHandler) 的方式顯式通知客戶端。
依托于這些功能,ZooKeeper 常被用來實現集群成員管理、分布式鎖、領導者選舉等功能。Kafka 控制器大量使用 Watch 功能實現對集群的協調管理。我們一起來看一張圖片,它展示的是 Kafka 在 ZooKeeper 中創建的 znode 分布。你不用了解每個 znode 的作用,但你可以大致體會下 Kafka 對 ZooKeeper 的依賴。
圖中幾乎把我們能想到的所有 Kafka 集群的數據都囊括進來了。這里面比較重要的數據有:
所有主題信息。包括具體的分區信息,比如領導者副本是誰,ISR 集合中有哪些副本等。
所有 Broker 信息。包括當前都有哪些運行中的 Broker,哪些正在關閉中的 Broker 等。
所有涉及運維任務的分區。包括當前正在進行 Preferred 領導者選舉以及分區重分配的分區列表。
值得注意的是,這些數據其實在 ZooKeeper 中也保存了一份。每當控制器初始化時,它都會從 ZooKeeper 上讀取對應的元數據并填充到自己的緩存中。有了這些數據,控制器就能對外提供數據服務了。這里的對外主要是指對其他 Broker 而言,控制器通過向這些 Broker 發送請求的方式將這些數據同步到其他 Broker 上。
我們在前面強調過,在 Kafka 集群運行過程中,只能有一臺 Broker 充當控制器的角色,那么這就存在單點失效(Single Point of Failure)的風險,Kafka 是如何應對單點失效的呢?答案就是,為控制器提供故障轉移功能,也就是說所謂的 Failover。
故障轉移指的是,當運行中的控制器突然宕機或意外終止時,Kafka 能夠快速地感知到,并立即啟用備用控制器來代替之前失敗的控制器。這個過程就被稱為 Failover,該過程是自動完成的,無需你手動干預。
最開始時,Broker 0 是控制器。當 Broker 0 宕機后,ZooKeeper 通過 Watch 機制感知到并刪除了 /controller 臨時節點。之后,所有存活的 Broker 開始競選新的控制器身份。Broker 3 最終贏得了選舉,成功地在 ZooKeeper 上重建了 /controller 節點。之后,Broker 3 會從 ZooKeeper 中讀取集群元數據信息,并初始化到自己的緩存中。至此,控制器的 Failover 完成,可以行使正常的工作職責了。
在 Kafka 0.11 版本之前,控制器的設計是相當繁瑣的,代碼更是有些混亂,這就導致社區中很多控制器方面的 Bug 都無法修復。控制器是多線程的設計,會在內部創建很多個線程。比如,控制器需要為每個 Broker 都創建一個對應的 Socket 連接,然后再創建一個專屬的線程,用于向這些 Broker 發送特定請求。如果集群中的 Broker 數量很多,那么控制器端需要創建的線程就會很多。另外,控制器連接 ZooKeeper 的會話,也會創建單獨的線程來處理 Watch 機制的通知回調。除了以上這些線程,控制器還會為主題刪除創建額外的 I/O 線程。
比起多線程的設計,更糟糕的是,這些線程還會訪問共享的控制器緩存數據。我們都知道,多線程訪問共享可變數據是維持線程安全最大的難題。為了保護數據安全性,控制器不得不在代碼中大量使用ReentrantLock 同步機制,這就進一步拖慢了整個控制器的處理速度。
鑒于這些原因,社區于 0.11 版本重構了控制器的底層設計,最大的改進就是,把多線程的方案改成了單線程加事件隊列的方案。我直接使用社區的一張圖來說明。
從這張圖中,我們可以看到,社區引入了一個事件處理線程,統一處理各種控制器事件,然后控制器將原來執行的操作全部建模成一個個獨立的事件,發送到專屬的事件隊列中,供此線程消費。這就是所謂的單線程 + 隊列的實現方式。
值得注意的是,這里的單線程不代表之前提到的所有線程都被“干掉”了,控制器只是把緩存狀態變更方面的工作委托給了這個線程而已。
這個方案的最大好處在于,控制器緩存中保存的狀態只被一個線程處理,因此不再需要重量級的線程同步機制來維護線程安全,Kafka 不用再擔心多線程并發訪問的問題,非常利于社區定位和診斷控制器的各種問題。事實上,自 0.11 版本重構控制器代碼后,社區關于控制器方面的 Bug 明顯少多了,這也說明了這種方案是有效的。
針對控制器的第二個改進就是,將之前同步操作 ZooKeeper 全部改為異步操作。ZooKeeper 本身的 API 提供了同步寫和異步寫兩種方式。之前控制器操作 ZooKeeper 使用的是同步的 API,性能很差,集中表現為,當有大量主題分區發生變更時,ZooKeeper 容易成為系統的瓶頸。新版本 Kafka 修改了這部分設計,完全摒棄了之前的同步 API 調用,轉而采用異步 API 寫入 ZooKeeper,性能有了很大的提升。根據社區的測試,改成異步之后,ZooKeeper 寫入提升了 10 倍!
除了以上這些,社區最近又發布了一個重大的改進!之前 Broker 對接收的所有請求都是一視同仁的,不會區別對待。這種設計對于控制器發送的請求非常不公平,因為這類請求應該有更高的優先級。
舉個簡單的例子,假設我們刪除了某個主題,那么控制器就會給該主題所有副本所在的 Broker 發送一個名為StopReplica的請求。如果此時 Broker 上存有大量積壓的 Produce 請求,那么這個 StopReplica 請求只能排隊等。如果這些 Produce 請求就是要向該主題發送消息的話,這就顯得很諷刺了:主題都要被刪除了,處理這些 Produce 請求還有意義嗎?此時最合理的處理順序應該是,賦予 StopReplica 請求更高的優先級,使它能夠得到搶占式的處理。
這在 2.2 版本之前是做不到的。不過自 2.2 開始,Kafka 正式支持這種不同優先級請求的處理。簡單來說,Kafka 將控制器發送的請求與普通數據類請求分開,實現了控制器請求單獨處理的邏輯。鑒于這個改進還是很新的功能,具體的效果我們就拭目以待吧。
當你覺得控制器組件出現問題時,比如主題無法刪除了,或者重分區 hang 住了,你不用重啟 Kafka Broker 或控制器。有一個簡單快速的方式是,去 ZooKeeper 中手動刪除 /controller 節點。具體命令是 rmr /controller。這樣做的好處是,既可以引發控制器的重選舉,又可以避免重啟 Broker 導致的消息處理中斷。
上述就是小編為大家分享的Kafka的控制器controller如何理解了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。