溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Kafka的控制器controller如何理解

發(fā)布時(shí)間:2021-12-15 11:13:22 來源:億速云 閱讀:193 作者:柒染 欄目:大數(shù)據(jù)

這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)碛嘘P(guān)Kafka的控制器controller如何理解,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

一、控制器簡介

控制器組件(Controller),是 Apache Kafka 的核心組件。它的主要作用是在 Apache ZooKeeper 的幫助下管理和協(xié)調(diào)整個(gè) Kafka 集群。集群中任意一臺(tái) Broker 都能充當(dāng)控制器的角色,但是,在運(yùn)行過程中,只能有一個(gè) Broker 成為控制器,行使其管理和協(xié)調(diào)的職責(zé)。換句話說,每個(gè)正常運(yùn)轉(zhuǎn)的 Kafka 集群,在任意時(shí)刻都有且只有一個(gè)控制器。官網(wǎng)上有個(gè)名為 activeController 的 JMX 指標(biāo),可以幫助我們實(shí)時(shí)監(jiān)控控制器的存活狀態(tài)。這個(gè) JMX 指標(biāo)非常關(guān)鍵,你在實(shí)際運(yùn)維操作過程中,一定要實(shí)時(shí)查看這個(gè)指標(biāo)的值。下面,我們就來詳細(xì)說說控制器的原理和內(nèi)部運(yùn)行機(jī)制。

二、控制器的原理和內(nèi)部運(yùn)行機(jī)制

ZooKeeper介紹

     在開始之前,我先簡單介紹一下 Apache ZooKeeper 框架。要知道,控制器是重度依賴 ZooKeeper 的,因此,我們有必要花一些時(shí)間學(xué)習(xí)下 ZooKeeper 是做什么的。Apache ZooKeeper 是一個(gè)提供高可靠性的分布式協(xié)調(diào)服務(wù)框架。它使用的數(shù)據(jù)模型類似于文件系統(tǒng)的樹形結(jié)構(gòu),根目錄也是以“/”開始。該結(jié)構(gòu)上的每個(gè)節(jié)點(diǎn)被稱為 znode,用來保存一些元數(shù)據(jù)協(xié)調(diào)信息。如果以 znode 持久性來劃分,znode 可分為持久性 znode 和臨時(shí) znode。持久性 znode 不會(huì)因?yàn)?ZooKeeper 集群重啟而消失,而臨時(shí) znode 則與創(chuàng)建該 znode 的 ZooKeeper 會(huì)話綁定,一旦會(huì)話結(jié)束,該節(jié)點(diǎn)會(huì)被自動(dòng)刪除。
     ZooKeeper 賦予客戶端監(jiān)控 znode 變更的能力,即所謂的 Watch 通知功能。一旦 znode 節(jié)點(diǎn)被創(chuàng)建、刪除,子節(jié)點(diǎn)數(shù)量發(fā)生變化,抑或是 znode 所存的數(shù)據(jù)本身變更,ZooKeeper 會(huì)通過節(jié)點(diǎn)變更監(jiān)聽器 (ChangeHandler) 的方式顯式通知客戶端。
    依托于這些功能,ZooKeeper 常被用來實(shí)現(xiàn)集群成員管理、分布式鎖、領(lǐng)導(dǎo)者選舉等功能。Kafka 控制器大量使用 Watch 功能實(shí)現(xiàn)對(duì)集群的協(xié)調(diào)管理。我們一起來看一張圖片,它展示的是 Kafka 在 ZooKeeper 中創(chuàng)建的 znode 分布。你不用了解每個(gè) znode 的作用,但你可以大致體會(huì)下 Kafka 對(duì) ZooKeeper 的依賴。

Kafka的控制器controller如何理解
圖中幾乎把我們能想到的所有 Kafka 集群的數(shù)據(jù)都囊括進(jìn)來了。這里面比較重要的數(shù)據(jù)有:
    所有主題信息。包括具體的分區(qū)信息,比如領(lǐng)導(dǎo)者副本是誰,ISR 集合中有哪些副本等。
    所有 Broker 信息。包括當(dāng)前都有哪些運(yùn)行中的 Broker,哪些正在關(guān)閉中的 Broker 等。
    所有涉及運(yùn)維任務(wù)的分區(qū)。包括當(dāng)前正在進(jìn)行 Preferred 領(lǐng)導(dǎo)者選舉以及分區(qū)重分配的分區(qū)列表。

    值得注意的是,這些數(shù)據(jù)其實(shí)在 ZooKeeper 中也保存了一份。每當(dāng)控制器初始化時(shí),它都會(huì)從 ZooKeeper 上讀取對(duì)應(yīng)的元數(shù)據(jù)并填充到自己的緩存中。有了這些數(shù)據(jù),控制器就能對(duì)外提供數(shù)據(jù)服務(wù)了。這里的對(duì)外主要是指對(duì)其他 Broker 而言,控制器通過向這些 Broker 發(fā)送請(qǐng)求的方式將這些數(shù)據(jù)同步到其他 Broker 上。

控制器故障轉(zhuǎn)移

    我們?cè)谇懊鎻?qiáng)調(diào)過,在 Kafka 集群運(yùn)行過程中,只能有一臺(tái) Broker 充當(dāng)控制器的角色,那么這就存在單點(diǎn)失效(Single Point of Failure)的風(fēng)險(xiǎn),Kafka 是如何應(yīng)對(duì)單點(diǎn)失效的呢?答案就是,為控制器提供故障轉(zhuǎn)移功能,也就是說所謂的 Failover。
    故障轉(zhuǎn)移指的是,當(dāng)運(yùn)行中的控制器突然宕機(jī)或意外終止時(shí),Kafka 能夠快速地感知到,并立即啟用備用控制器來代替之前失敗的控制器。這個(gè)過程就被稱為 Failover,該過程是自動(dòng)完成的,無需你手動(dòng)干預(yù)。
Kafka的控制器controller如何理解
    最開始時(shí),Broker 0 是控制器。當(dāng) Broker 0 宕機(jī)后,ZooKeeper 通過 Watch 機(jī)制感知到并刪除了 /controller 臨時(shí)節(jié)點(diǎn)。之后,所有存活的 Broker 開始競選新的控制器身份。Broker 3 最終贏得了選舉,成功地在 ZooKeeper 上重建了 /controller 節(jié)點(diǎn)。之后,Broker 3 會(huì)從 ZooKeeper 中讀取集群元數(shù)據(jù)信息,并初始化到自己的緩存中。至此,控制器的 Failover 完成,可以行使正常的工作職責(zé)了。

控制器內(nèi)部設(shè)計(jì)原理

    在 Kafka 0.11 版本之前,控制器的設(shè)計(jì)是相當(dāng)繁瑣的,代碼更是有些混亂,這就導(dǎo)致社區(qū)中很多控制器方面的 Bug 都無法修復(fù)??刂破魇嵌嗑€程的設(shè)計(jì),會(huì)在內(nèi)部創(chuàng)建很多個(gè)線程。比如,控制器需要為每個(gè) Broker 都創(chuàng)建一個(gè)對(duì)應(yīng)的 Socket 連接,然后再創(chuàng)建一個(gè)專屬的線程,用于向這些 Broker 發(fā)送特定請(qǐng)求。如果集群中的 Broker 數(shù)量很多,那么控制器端需要?jiǎng)?chuàng)建的線程就會(huì)很多。另外,控制器連接 ZooKeeper 的會(huì)話,也會(huì)創(chuàng)建單獨(dú)的線程來處理 Watch 機(jī)制的通知回調(diào)。除了以上這些線程,控制器還會(huì)為主題刪除創(chuàng)建額外的 I/O 線程。
    比起多線程的設(shè)計(jì),更糟糕的是,這些線程還會(huì)訪問共享的控制器緩存數(shù)據(jù)。我們都知道,多線程訪問共享可變數(shù)據(jù)是維持線程安全最大的難題。為了保護(hù)數(shù)據(jù)安全性,控制器不得不在代碼中大量使用ReentrantLock 同步機(jī)制,這就進(jìn)一步拖慢了整個(gè)控制器的處理速度。
    鑒于這些原因,社區(qū)于 0.11 版本重構(gòu)了控制器的底層設(shè)計(jì),最大的改進(jìn)就是,把多線程的方案改成了單線程加事件隊(duì)列的方案。我直接使用社區(qū)的一張圖來說明。

Kafka的控制器controller如何理解
    從這張圖中,我們可以看到,社區(qū)引入了一個(gè)事件處理線程,統(tǒng)一處理各種控制器事件,然后控制器將原來執(zhí)行的操作全部建模成一個(gè)個(gè)獨(dú)立的事件,發(fā)送到專屬的事件隊(duì)列中,供此線程消費(fèi)。這就是所謂的單線程 + 隊(duì)列的實(shí)現(xiàn)方式。
值得注意的是,這里的單線程不代表之前提到的所有線程都被“干掉”了,控制器只是把緩存狀態(tài)變更方面的工作委托給了這個(gè)線程而已。
    這個(gè)方案的最大好處在于,控制器緩存中保存的狀態(tài)只被一個(gè)線程處理,因此不再需要重量級(jí)的線程同步機(jī)制來維護(hù)線程安全,Kafka 不用再擔(dān)心多線程并發(fā)訪問的問題,非常利于社區(qū)定位和診斷控制器的各種問題。事實(shí)上,自 0.11 版本重構(gòu)控制器代碼后,社區(qū)關(guān)于控制器方面的 Bug 明顯少多了,這也說明了這種方案是有效的。
    針對(duì)控制器的第二個(gè)改進(jìn)就是,將之前同步操作 ZooKeeper 全部改為異步操作。ZooKeeper 本身的 API 提供了同步寫和異步寫兩種方式。之前控制器操作 ZooKeeper 使用的是同步的 API,性能很差,集中表現(xiàn)為,當(dāng)有大量主題分區(qū)發(fā)生變更時(shí),ZooKeeper 容易成為系統(tǒng)的瓶頸。新版本 Kafka 修改了這部分設(shè)計(jì),完全摒棄了之前的同步 API 調(diào)用,轉(zhuǎn)而采用異步 API 寫入 ZooKeeper,性能有了很大的提升。根據(jù)社區(qū)的測(cè)試,改成異步之后,ZooKeeper 寫入提升了 10 倍!

三、社區(qū)工作

    除了以上這些,社區(qū)最近又發(fā)布了一個(gè)重大的改進(jìn)!之前 Broker 對(duì)接收的所有請(qǐng)求都是一視同仁的,不會(huì)區(qū)別對(duì)待。這種設(shè)計(jì)對(duì)于控制器發(fā)送的請(qǐng)求非常不公平,因?yàn)檫@類請(qǐng)求應(yīng)該有更高的優(yōu)先級(jí)。
    舉個(gè)簡單的例子,假設(shè)我們刪除了某個(gè)主題,那么控制器就會(huì)給該主題所有副本所在的 Broker 發(fā)送一個(gè)名為StopReplica的請(qǐng)求。如果此時(shí) Broker 上存有大量積壓的 Produce 請(qǐng)求,那么這個(gè) StopReplica 請(qǐng)求只能排隊(duì)等。如果這些 Produce 請(qǐng)求就是要向該主題發(fā)送消息的話,這就顯得很諷刺了:主題都要被刪除了,處理這些 Produce 請(qǐng)求還有意義嗎?此時(shí)最合理的處理順序應(yīng)該是,賦予 StopReplica 請(qǐng)求更高的優(yōu)先級(jí),使它能夠得到搶占式的處理。
    這在 2.2 版本之前是做不到的。不過自 2.2 開始,Kafka 正式支持這種不同優(yōu)先級(jí)請(qǐng)求的處理。簡單來說,Kafka 將控制器發(fā)送的請(qǐng)求與普通數(shù)據(jù)類請(qǐng)求分開,實(shí)現(xiàn)了控制器請(qǐng)求單獨(dú)處理的邏輯。鑒于這個(gè)改進(jìn)還是很新的功能,具體的效果我們就拭目以待吧。
    當(dāng)你覺得控制器組件出現(xiàn)問題時(shí),比如主題無法刪除了,或者重分區(qū) hang 住了,你不用重啟 Kafka Broker 或控制器。有一個(gè)簡單快速的方式是,去 ZooKeeper 中手動(dòng)刪除 /controller 節(jié)點(diǎn)。具體命令是 rmr /controller。這樣做的好處是,既可以引發(fā)控制器的重選舉,又可以避免重啟 Broker 導(dǎo)致的消息處理中斷。

上述就是小編為大家分享的Kafka的控制器controller如何理解了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI