Kafka源碼分析9:Controller控制器的原理(圖解+秒懂+史上最全)


文章很長,建議收藏起來,慢慢讀! Java 高並發 發燒友社群:瘋狂創客圈 奉上以下珍貴的學習資源:


推薦:入大廠 、做架構、大力提升Java 內功 的 精彩博文

入大廠 、做架構、大力提升Java 內功 必備的精彩博文 2021 秋招漲薪1W + 必備的精彩博文
1:Redis 分布式鎖 (圖解-秒懂-史上最全) 2:Zookeeper 分布式鎖 (圖解-秒懂-史上最全)
3: Redis與MySQL雙寫一致性如何保證? (面試必備) 4: 面試必備:秒殺超賣 解決方案 (史上最全)
5:面試必備之:Reactor模式 6: 10分鍾看懂, Java NIO 底層原理
7:TCP/IP(圖解+秒懂+史上最全) 8:Feign原理 (圖解)
9:DNS圖解(秒懂 + 史上最全 + 高薪必備) 10:CDN圖解(秒懂 + 史上最全 + 高薪必備)
11: 分布式事務( 圖解 + 史上最全 + 吐血推薦 ) 12:seata AT模式實戰(圖解+秒懂+史上最全)
13:seata 源碼解讀(圖解+秒懂+史上最全) 14:seata TCC模式實戰(圖解+秒懂+史上最全)

Java 面試題 30個專題 , 史上最全 , 面試必刷 阿里、京東、美團... 隨意挑、橫着走!!!
1: JVM面試題(史上最強、持續更新、吐血推薦) 2:Java基礎面試題(史上最全、持續更新、吐血推薦
3:架構設計面試題 (史上最全、持續更新、吐血推薦) 4:設計模式面試題 (史上最全、持續更新、吐血推薦)
17、分布式事務面試題 (史上最全、持續更新、吐血推薦) 一致性協議 (史上最全)
29、多線程面試題(史上最全) 30、HR面經,過五關斬六將后,小心陰溝翻船!
9.網絡協議面試題(史上最全、持續更新、吐血推薦) 更多專題, 請參見【 瘋狂創客圈 高並發 總目錄

SpringCloud 精彩博文
nacos 實戰(史上最全) sentinel (史上最全+入門教程)
SpringCloud gateway (史上最全) 更多專題, 請參見【 瘋狂創客圈 高並發 總目錄

背景:

下一個視頻版本,從架構師視角,尼恩為大家打造史上最強kafka源碼視頻

並且,進一步,帶大家實現一個超高質量的項目實操:10WQPS超高並發消息隊列架構與實操

why kafka:

kafka 是高性能、高並發應用的經典案例,從技術學習、架構學習的角度來講,渾身是寶。 netty 僅僅是通訊架構,kafka還有存儲架構、高並發架構、高可用架構等等,都是經典中的經典。

但是,kafka很難,大家要做好思想准備。不過,跟着尼恩一起學架構,估計大家也不難了。

最終的目標,帶大家穿透kafka, 掌握其存儲架構、高並發架構、高可用架構的精髓。

最后,結合netty高性能架構,最終手寫一個10WQPS超高並發消息隊列。

此視頻版本的整體的次序:

  • 首先,開始Kafka源碼分析,對kafka來一次徹底穿透
  • 然后,10WQPS超高並發消息隊列架構與實操,結合牛逼的Seata 源碼中的RPC框架

在這里插入圖片描述

此文為Kafka源碼分析之9

本系列博客的具體內容,請參見 Java 高並發 發燒友社群:瘋狂創客圈

其實,很多小伙伴,想學kafka,只是,其太難了

在這里插入圖片描述

尼恩帶大家學架構的目標: 把kafka中的所有高並發、高性能、高可用架構,完全消化,完全吸收,最終再造kafka, 大大提升自己的架構能力, 向架構師前進一大步。

Kafka源碼分析9:Controller控制器的原理

Controller,是Apache Kafka的核心組件非常重要。它的主要作用是在Apache Zookeeper的幫助下管理和協調控制整個Kafka集群。

在整個Kafka集群中,如果Controller故障異常,有可能會影響到生產和消費。所以,我們需要對其狀態、選舉、日志等做全面的監控。

集群中任意一台 Broker 都能充當控制器的角色,但是,在運行過程中,只能有一個 Broker 成為控制器,行使其管理和協調的職責。換句話說,每個正常運轉的 Kafka 集群,在任意時刻都有且只有一個控制器。

要宏觀的了解controller的位置,咱們還是先從分布式系統的集群架構說起

分布式的系統的集群架構分類

分布式系統中,由誰來管理集群的元數據信息和狀態信息呢?

兩種架構模式:

  • 中心化架構(主從架構)

  • 去中心話架構(p2p架構)

主從(或者說Leader-Follower)架構

主從架構模式中,Leader來管理集群的元數據信息和狀態信息。

Leader可以是固定的,也可以是通過選舉出來的。

Leader-Follower架構,也叫Master-Slave架構。

細數主流的開源分布式系統,你會發現四處都是Master-Slave架構的影子,是最常用的設計套路之一,深入理解了Master-Slave架構對於理解這些系統有很大的幫助

下面來簡單介紹一下有哪些著名的分布式框架采用了Master-Slave架構:

1.HDFS

NameNode和DataNode實際上是Master-Slave模式,NameNode作為Master進行集群和元數據管理,DataNode負責實際的數據存儲。

img

2.Elasticsearch

Master-Slave模式,Master進行集群和元數據管理,Data Node作為Slave節點,負責實際數據的索引和搜索操作。

img

3.Hbase

HMastet和HRegionServer也是Master-Slave架構,HMaster負責Region分配,協調HRegionServer,提供管理功能,而HRegionServer負責維護HRegion。

img

img

Flink的架構模式也是類似Master-Slave模式,JobManager相當於Master,負責集群任務調度和資源管理,TaskManager相當於Slave負責具體節點的資源申請和管理。

5.kafka

Kafka作為一個高效的分布式消息系統,也采用了主從(或者說Leader-Follower)的設計思路

kafka通過選舉的方式,進行Leader角色的選舉,從所有的節點中,選出一個broker節點,作為leader角色,或者說master角色。

選出的角色,叫做controller 。

controller 負責元數據的管理和狀態信息的管理。

在這里插入圖片描述

P2P的模式

采用了P2P的模式,完全去中心化,如果 Redis Cluster集群。

Redis Cluster是一種服務器Sharding技術(分片和路由都是在服務端實現),采用多主多從,每一個分區都是由一個Redis主機和多個從機組成,片區和片區之間是相互平行的。

img

Redis Cluster如何管理集群的狀態信息呢? 通過Gossip協議。

Gossip算法如其名,靈感來自辦公室八卦,只要一個人八卦一下,在有限的時間內所有的人都會知道該八卦的信息,這種方式也與病毒傳播類似,因此Gossip有眾多的別名“閑話算法”、“疫情傳播算法”、“病毒感染算法”、“謠言傳播算法”。

但Gossip並不是一個新東西,之前的泛洪查找、路由算法都歸屬於這個范疇,不同的是Gossip給這類算法提供了明確的語義、具體實施方法及收斂性證明。

Gossip 過程是由種子節點發起,當一個種子節點有狀態需要更新到網絡中的其他節點時,它會隨機的選擇周圍幾個節點散播消息,收到消息的節點也會重復該過程,直至最終網絡中所有的節點都收到了消息。這個過程可能需要一定的時間,由於不能保證某個時刻所有節點都收到消息,但是理論上最終所有節點都會收到消息,因此它是一個最終一致性協議。

這里一共有 16 個節點,節點 1 為初始被感染節點,通過 Gossip 過程,最終所有節點都被感染:

img

Controller是什么

Controller,是Apache Kafka的核心組件。

Controller的主要作用是在Apache Zookeeper的幫助下管理和協調控制整個Kafka集群,管理元數據,管理集群狀態。

集群中的任意一台Broker都能充當Controller的角色.

但是,在整個集群運行過程中,只能有一個Broker成為Controller。

Controller的位置

也就是說,每個正常運行的Kafka集群,在任何時刻都有且只有一個Controller

img

controller的兩大職能

controller的兩大職能

  • 集群元數據的管理
  • 集群節點的協調職能

圖解:controller的集群元數據的管理職能

controller的元數據緩存架構

kafka的元數據信息,持久化在ZK中,具體如下圖:

在這里插入圖片描述

每一次元數據的使用,都去訪問zk,性能比較低。

與java程序提升性能的策略類似,controller也使用了緩存的架構。

只不過,使用的是進程內的緩存,具體如下圖:

在這里插入圖片描述

Controller緩存的元數據

img

其中比較重要的數據有:

所有主題信息。

包括具體的分區信息,比如領導者副本是誰,ISR集合中有哪些副本等。

所有Broker信息。

包括當前都有哪些運行中的Broker,哪些正在關閉中的Broker等。

所有涉及運維任務的分區。

包括當前正在進行Preferred領導者選舉以及分區重分配的分區列表。

這些數據其實在ZooKeeper中也保存了一份。

緩存的作用

每當控制器初始化時,它都會從ZooKeeper上讀取對應的元數據並填充到自己的緩存中。

而Broker上元數據的更新都是由Controller通知完成的,Broker並不從Zookeeper獲取元數據信息。

在這里插入圖片描述

Controller的集群節點的協調職能

9項細致的協調工作

下面以文字形式列舉Controller需要做些什么集群節點的協調職能,大致9項:

  1. 當Producer或Consumer通過MetadataRequest請求查詢Partition元數據(如Leader和ISR信息)時,將發生變化的Partition元數據廣播給各個Broker。
  2. 處理ControlledShudownRequest請求,該請求用於優雅地關閉一個Broker(主要是會主動刪除ZK中對應的Broker節點,減少對應Partition不可用的時間)。
  3. 啟動並管理Partition狀態機組件(PartitionStateMachine)和Replica狀態機組件(ReplicaStateMachine)。
  4. 注冊TopicChangeListener監聽器,監聽ZK的/brokers/topics節點,處理Topic的增刪操作;注冊TopicDeletionListener監聽器,監聽ZK的/admin/delete_topics節點,用來實際執行刪除Topic的動作。
  5. 注冊PartitionModificationsListener監聽器,監聽ZK中各個/brokers/topics/<topic>節點,處理Topic的Partition擴容和縮容操作。
  6. 注冊PreferredReplicaElectionListener監聽器,監聽ZK的/admin/preferred_replica_election節點,處理最優Replica的重選舉。
  7. 注冊IsrChangeNotificetionListener監聽器,監聽ZK的/isr_change_notification節點,處理ISR(in-sync replicas)集合發生變化的Partition。
  8. 注冊PartitionReassignmentListener監聽器,監聽ZK的/admin/reassign_partitions節點,用於重新分配各Partition的Leader和Follower。
  9. 注冊BrokerChangeListener監聽器,監聽ZK的/brokers/ids節點,觸發Broker的上下線操作。

如果上面的9項,還比較抽象,還請不要捉急,容我慢慢道來。

5類協調職能梳理

歸類一下,相對就簡單一下,Controller職責大致分為5類:

  • 主題管理
  • 分區重分配
  • Preferred leader選舉
  • 集群成員管理(Broker上下線)
  • 數據服務(向其他Broker提供數據服務) 。

它們分別是:

UpdateMetadataRequest:更新元數據請求。

topic分區狀態經常會發生變更(比如leader重新選舉了或副本集合變化了等)。

由於當前clients只能與分區的leader Broker進行交互,那么一旦發生變更,controller會將最新的元數據廣播給所有存活的Broker。

具體方式就是給所有Broker發送UpdateMetadataRequest請求。

CreateTopics: 創建topic請求。

當前不管是通過API方式、腳本方式抑或是CreateTopics請求方式來創建topic,做法幾乎都是在Zookeeper的/brokers/topics下創建znode來觸發創建邏輯,而controller會監聽該path下的變更來執行真正的“創建topic”邏輯。

DeleteTopics:刪除topic請求。

和CreateTopics類似,也是通過創建Zookeeper下的/admin/delete_topics/ 節點來觸發刪除topic,controller執行真正的邏輯。

分區重分配:

即kafka-reassign-partitions腳本做的事情。

同樣是與Zookeeper結合使用,腳本寫入/admin/reassign_partitions節點來觸 發,controller負責按照方案分配分區。

Preferred leader分配:

preferred leader選舉當前有兩種觸發方式:自動觸發(auto.leader.rebalance.enable=true)和kafka-preferred-replica-election腳本觸發。

兩者“玩法”相同,向Zookeeper的/admin/preferred_replica_election寫數據,controller提取數據執行preferred leader分配。

分區擴展:即增加topic分區數。

標准做法也是通過kafka-reassign-partitions腳本完成,不過用戶可直接往Zookeeper中寫數據來實現,比如直接把新增分區的副本集合寫入到/brokers/topics/ 下,然后controller會為你自動地選出leader並增加分區。

集群擴展:

新增broker時Zookeeper中/brokers/ids下會新增znode,controller自動完成服務發現的工作。

broker崩潰:

同樣地,controller通過Zookeeper可實時偵測broker狀態。一旦有broker掛掉了,controller可立即感知並為受影響分區選舉新的leader。

ControlledShutdown:

broker除了崩潰,還能“優雅”地退出。

broker一旦自行終止,controller會接收到一個 ControlledShudownRequest請求,然后controller會妥善處理該請求並執行各種收尾工作。

Controller leader選舉:

controller必然要提供自己的leader選舉以防這個全局唯一的組件崩潰宕機導致服務中斷。

這個功能是通過 Zookeeper的幫助實現的。

Controller內部結構

最后來看看Controller的內部結構簡圖,如下所示。

img

由圖可見,Controller內部結構主要由以下5部分組成。

  1. ZK監聽器:

    已經說過了,不再廢話。

  2. 定時任務:

    舉個例子,假設我們將auto.leader.rebalance.enable參數設為true,那么就會啟動名為auto-leader-rebalance-task的定時任務來自動維護最優Replica的平衡。

  3. Controller上下文:

    元數據的本地緩存,就集中在此上下文對象中。

    在Controller初始化階段,從ZK中已存儲的數據建立,並在Controller的生命周期中一直維護。包含集群Broker可達性信息,與所有Topic、Partition、Replica的狀態信息。

  4. 事件隊列:

    本質上為FIFO的阻塞隊列(LinkedBlockingQueue),承載各個監聽器、定時任務投遞過來的狀態變更信息,這些信息都包裝為事件。

    Controller 端有多個線程向事件隊列寫入不同種類的事件,比如,ZooKeeper 端注冊的 Watcher 線程、KafkaRequestHandler 線程、Kafka 定時任務線程,等等。而在事件隊列的另一端,只有一個名為 ControllerEventThread 的線程專門負責“消費”或處理隊列中的事件。這就是所謂的單線程事件隊列模型。

  5. 事件處理線程:

    顧名思義,只有單線程,用來處理各個事件,並將它們的結果反映到Controller上下文,以及異步地propagate到各個Broker中。使用單線程的好處是無需關心多線程的同步,無鎖機制可以提升性能。

Broker如何成為Controller

非常簡單:

通過競爭創建zk的znode節點完成,最先在Zookeeper上創建臨時節點/controller成功的Broker就是Controller。

在這里插入圖片描述

對應的znode的路徑為/controller

在這里插入圖片描述

znode的路徑的代碼如下:

img

Controller如何監控其他的broker

當broker節點因故障離開Kafka集群時,broker中存在的leader分區將不可用(因為客戶端只對leader分區進行讀寫)

為了最大限度地減少停機時間,需要快速找到替代的領導分區。Controller可以從zookeeper watch獲取通知信息。Zookeeper給了客戶端監聽znode變化的能力,也就是所謂的watch通知功能。

一旦znode節點創建、刪除、子節點數量發生變化,或者znode中存儲的數據本身發生變化,Zookeeper會通過節點變化處理程序顯式通知客戶端。

當Broker宕機或主動關閉時,Broker與Zookeeper的會話結束,znode會被自動刪除。同樣的,Zookeeper的watch機制把這個變化推送給Controller,讓Controller知道有Broker down或者up,這樣Controller就可以進行后續的協調操作。

Controller將收到通知並對其采取行動,以確定Broker上的哪些分區將成為Leader partition。然后,它會通知每個相關的Broker,或者Broker上的topic partition將成為leader partition,或者LeaderAndIsrRequest從新的leader分區復制數據。

總之:

Controller重度依賴Zookeeper,依賴zookeepr保存元數據,依賴zookeeper進行服務發現。Controller大量使用Watch功能實現對集群的協調管理。

controller腦裂(多個controller)問題

腦裂問題出現的可能情況:

情況一:創建topic成功,但是produce的時候,卻報unknown partition的錯誤,但zk上卻顯示了每個partition的leader信息;
情況二: 給某個topic增加分區,zk顯示已有增加的分區信息,但是依舊報找不到新增加的分區信息錯誤
原因:多個controller,導致元數據不一致;

解決辦法:

  1. zk上找到最新的controller
  2. 將其余幾個過期的controller重啟

原因分析:controller進行Full GC停頓時間太長超過zookeeper session timeout,導致kafka誤以為controller已經掛掉,於是進行新一輪的controller選舉。 當舊的controller重新恢復后,還在進行controller的邏輯。因此會出現多個controller的情況

如何避免Controller出現裂腦

如果Controller所在的Broker故障,Kafka集群必須有新的Controller,否則集群將無法正常工作。這兒存在一個問題。很難確定Broker是宕機還是只是暫時的故障。

但是,為了使集群正常運行,必須選擇新的Controller。如果之前更換的Controller又正常了,不知道自己已經更換了,那么集群中就會出現兩個Controller。

其實這種情況是很容易發生的。

例如,由於垃圾回收(fullGC),一個Controller被認為是死的,並選擇了一個新的控制器。在fullGC的情況下,在原Controller眼里沒有任何變化,Broker甚至不知道自己已經被暫停了。因此,它將繼續充當當前Controller,這在分布式系統中很常見,稱為裂腦

在這里插入圖片描述

在fullGC的情況下,在原Controller眼里沒有任何變化,Broker甚至不知道自己已經被暫停了。

在這里插入圖片描述

現在,集群中有兩個Controller,可能會一起發出相互沖突的事件,這會導致腦裂。

腦裂之后,可能會導致嚴重的不一致。所以需要一種方法來區分誰是集群的最新Controller。

kafka腦裂的補救方案:

Kafka是通過使用epoch number來處理,epoch number只是一個單調遞增的數。第一次選擇控制器時,epoch number值為1。如果再次選擇新控制器,epoch number為2,依次單調遞增。

重點是:epoch number記錄在Zookeepr的一個永久節點controller_epoch。

每個新選擇的Controller通過zookeeper的條件遞增操作獲得一個新的、更大的epoch number。

當其他Broker知道當前的epoch number時,如果他們從Controller收到包含舊(較小)epoch number的消息,則它們將被忽略。

即Broker根據最大的epoch number來區分最新的Controller。

在這里插入圖片描述

上圖中,Broker2向Broker1下發命令:

將Broker1上的partitionA做為leader,消息的epoch number值為1;

假設,同時Broker3也向Broker1發送同樣的命令。

不同的是,Broker3消息的epoch number值為2,此時broker1只監聽broker3的命令(由於其epoch號大),而會忽略broker3的命令,以免發生腦裂。

其實這種腦裂情況,是很容易發生的。

kafka的補救方案,只是保證集群可用,但是過期的controller,還是需要找出來,將過期的controller重啟。

Controller控制器的監控

官網上有個名為 activeController 的 JMX 指標,可以幫助我們實時監控控制器的存活狀態。這個 JMX 指標非常關鍵,你在實際運維操作過程中,一定要實時查看這個指標的值。

參考文獻

https://blog.csdn.net/weixin_39025362/article/details/108420492

https://www.cnblogs.com/boanxin/p/13618431.html

https://www.jianshu.com/p/7a61a2aa09fc

https://www.cnblogs.com/boanxin/p/13696136.html

https://www.cnblogs.com/listenfwind/p/12465409.html

https://www.shangmayuan.com/a/5e15939288954d3cb3ad613e.html

https://my.oschina.net/u/3070368/blog/4338739

https://www.cnblogs.com/shimingjie/p/10374451.html

https://www.bbsmax.com/A/VGzlAONYJb/

https://baijiahao.baidu.com/s?id=1707530675869255847&wfr=spider&for=pc


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM