文章很長,建議收藏起來,慢慢讀! Java 高並發 發燒友社群:瘋狂創客圈 奉上以下珍貴的學習資源:
-
免費贈送 經典圖書:《Java高並發核心編程(卷1)》 面試必備 + 大廠必備 +漲薪必備 加尼恩免費領
-
免費贈送 經典圖書:《Java高並發核心編程(卷2)》 面試必備 + 大廠必備 +漲薪必備 加尼恩免費領
-
免費贈送 經典圖書:《Netty Zookeeper Redis 高並發實戰》 面試必備 + 大廠必備 +漲薪必備 加尼恩免費領
-
免費贈送 經典圖書:《SpringCloud Nginx高並發核心編程》 面試必備 + 大廠必備 +漲薪必備 加尼恩免費領
-
免費贈送 資源寶庫: Java 必備 百度網盤資源大合集 價值>10000元 加尼恩領取
推薦:入大廠 、做架構、大力提升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負責實際的數據存儲。
2.Elasticsearch
Master-Slave模式,Master進行集群和元數據管理,Data Node作為Slave節點,負責實際數據的索引和搜索操作。
3.Hbase
HMastet和HRegionServer也是Master-Slave架構,HMaster負責Region分配,協調HRegionServer,提供管理功能,而HRegionServer負責維護HRegion。
4.Flink
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主機和多個從機組成,片區和片區之間是相互平行的。
Redis Cluster如何管理集群的狀態信息呢? 通過Gossip協議。
Gossip算法如其名,靈感來自辦公室八卦,只要一個人八卦一下,在有限的時間內所有的人都會知道該八卦的信息,這種方式也與病毒傳播類似,因此Gossip有眾多的別名“閑話算法”、“疫情傳播算法”、“病毒感染算法”、“謠言傳播算法”。
但Gossip並不是一個新東西,之前的泛洪查找、路由算法都歸屬於這個范疇,不同的是Gossip給這類算法提供了明確的語義、具體實施方法及收斂性證明。
Gossip 過程是由種子節點發起,當一個種子節點有狀態需要更新到網絡中的其他節點時,它會隨機的選擇周圍幾個節點散播消息,收到消息的節點也會重復該過程,直至最終網絡中所有的節點都收到了消息。這個過程可能需要一定的時間,由於不能保證某個時刻所有節點都收到消息,但是理論上最終所有節點都會收到消息,因此它是一個最終一致性協議。
這里一共有 16 個節點,節點 1 為初始被感染節點,通過 Gossip 過程,最終所有節點都被感染:
Controller是什么
Controller,是Apache Kafka的核心組件。
Controller的主要作用是在Apache Zookeeper的幫助下管理和協調控制整個Kafka集群,管理元數據,管理集群狀態。
集群中的任意一台Broker都能充當Controller的角色.
但是,在整個集群運行過程中,只能有一個Broker成為Controller。
Controller的位置
也就是說,每個正常運行的Kafka集群,在任何時刻都有且只有一個Controller。
controller的兩大職能
controller的兩大職能
- 集群元數據的管理
- 集群節點的協調職能
圖解:controller的集群元數據的管理職能
controller的元數據緩存架構
kafka的元數據信息,持久化在ZK中,具體如下圖:
每一次元數據的使用,都去訪問zk,性能比較低。
與java程序提升性能的策略類似,controller也使用了緩存的架構。
只不過,使用的是進程內的緩存,具體如下圖:
Controller緩存的元數據
其中比較重要的數據有:
所有主題信息。
包括具體的分區信息,比如領導者副本是誰,ISR集合中有哪些副本等。
所有Broker信息。
包括當前都有哪些運行中的Broker,哪些正在關閉中的Broker等。
所有涉及運維任務的分區。
包括當前正在進行Preferred領導者選舉以及分區重分配的分區列表。
這些數據其實在ZooKeeper中也保存了一份。
緩存的作用
每當控制器初始化時,它都會從ZooKeeper上讀取對應的元數據並填充到自己的緩存中。
而Broker上元數據的更新都是由Controller通知完成的,Broker並不從Zookeeper獲取元數據信息。
Controller的集群節點的協調職能
9項細致的協調工作
下面以文字形式列舉Controller需要做些什么集群節點的協調職能,大致9項:
- 當Producer或Consumer通過MetadataRequest請求查詢Partition元數據(如Leader和ISR信息)時,將發生變化的Partition元數據廣播給各個Broker。
- 處理ControlledShudownRequest請求,該請求用於優雅地關閉一個Broker(主要是會主動刪除ZK中對應的Broker節點,減少對應Partition不可用的時間)。
- 啟動並管理Partition狀態機組件(PartitionStateMachine)和Replica狀態機組件(ReplicaStateMachine)。
- 注冊TopicChangeListener監聽器,監聽ZK的
/brokers/topics
節點,處理Topic的增刪操作;注冊TopicDeletionListener監聽器,監聽ZK的/admin/delete_topics
節點,用來實際執行刪除Topic的動作。 - 注冊PartitionModificationsListener監聽器,監聽ZK中各個
/brokers/topics/<topic>
節點,處理Topic的Partition擴容和縮容操作。 - 注冊PreferredReplicaElectionListener監聽器,監聽ZK的
/admin/preferred_replica_election
節點,處理最優Replica的重選舉。 - 注冊IsrChangeNotificetionListener監聽器,監聽ZK的
/isr_change_notification
節點,處理ISR(in-sync replicas)集合發生變化的Partition。 - 注冊PartitionReassignmentListener監聽器,監聽ZK的
/admin/reassign_partitions
節點,用於重新分配各Partition的Leader和Follower。 - 注冊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/
分區重分配:
即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/
集群擴展:
新增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的內部結構簡圖,如下所示。
由圖可見,Controller內部結構主要由以下5部分組成。
-
ZK監聽器:
已經說過了,不再廢話。
-
定時任務:
舉個例子,假設我們將
auto.leader.rebalance.enable
參數設為true,那么就會啟動名為auto-leader-rebalance-task
的定時任務來自動維護最優Replica的平衡。 -
Controller上下文:
元數據的本地緩存,就集中在此上下文對象中。
在Controller初始化階段,從ZK中已存儲的數據建立,並在Controller的生命周期中一直維護。包含集群Broker可達性信息,與所有Topic、Partition、Replica的狀態信息。
-
事件隊列:
本質上為FIFO的阻塞隊列(LinkedBlockingQueue),承載各個監聽器、定時任務投遞過來的狀態變更信息,這些信息都包裝為事件。
Controller 端有多個線程向事件隊列寫入不同種類的事件,比如,ZooKeeper 端注冊的 Watcher 線程、KafkaRequestHandler 線程、Kafka 定時任務線程,等等。而在事件隊列的另一端,只有一個名為 ControllerEventThread 的線程專門負責“消費”或處理隊列中的事件。這就是所謂的單線程事件隊列模型。
-
事件處理線程:
顧名思義,只有單線程,用來處理各個事件,並將它們的結果反映到Controller上下文,以及異步地propagate到各個Broker中。使用單線程的好處是無需關心多線程的同步,無鎖機制可以提升性能。
Broker如何成為Controller
非常簡單:
通過競爭創建zk的znode節點完成,最先在Zookeeper上創建臨時節點/controller成功的Broker就是Controller。
對應的znode的路徑為/controller
znode的路徑的代碼如下:
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,導致元數據不一致;
解決辦法:
- zk上找到最新的controller
- 將其余幾個過期的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