自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

徹底搞懂如何通過 ZooKeeper 實(shí)現(xiàn)注冊中心

開發(fā) 架構(gòu)
我們針對微服務(wù)架構(gòu)中的一個核心技術(shù)組件,即注冊中心的基本模型做了展開,并基于 ZooKeeper 這款分布式協(xié)調(diào)工具重點(diǎn)分析了 Dubbo 中注冊中心的實(shí)現(xiàn)方式以及所具備的功能特性。

在微服務(wù)架構(gòu)中,注冊中心屬于一種服務(wù)治理組件。服務(wù)治理的需求來自于服務(wù)的數(shù)量,也來自于服務(wù)實(shí)例的動態(tài)性。在服務(wù)相互調(diào)用的過程中,每個服務(wù)首先需要高效地找到目標(biāo)服務(wù)才能執(zhí)行遠(yuǎn)程調(diào)用,因此服務(wù)治理所承載的服務(wù)注冊和發(fā)現(xiàn)機(jī)制就顯得非常重要了。

而注冊中心就是用來實(shí)現(xiàn)服務(wù)治理的工具,圍繞注冊中心涉及的角色包括以下三種:

  • 注冊中心:提供服務(wù)注冊和發(fā)現(xiàn)機(jī)制。
  • 服務(wù)提供者:將服務(wù)本身注冊到注冊中心,進(jìn)而暴露服務(wù)。
  • 服務(wù)消費(fèi)者:從注冊中心發(fā)現(xiàn)目標(biāo)服務(wù),進(jìn)而消費(fèi)服務(wù)。

微服務(wù)架構(gòu)中的服務(wù)提供者和服務(wù)消費(fèi)者可以認(rèn)為是注冊中心的客戶端,在服務(wù)內(nèi)部都嵌入了客戶端組件。

圖片圖片

上面這張圖所展示的注冊中心基本模型看起來比較簡單,但真正實(shí)現(xiàn)起來要考慮的點(diǎn)是非常多的。另一方面,如果想要實(shí)現(xiàn)這樣一個注冊中心,我們也需要選擇合適的工具。在今天的課程中,我們選擇的工具是功能、特性都非常適合構(gòu)建注冊中心的 ZooKeeper,讓我們一起來看一下。

ZooKeeper 與注冊中心

ZooKeeper 的物理結(jié)構(gòu)本質(zhì)上就是一個文件系統(tǒng),包含了一系列被稱為 ZNode 的節(jié)點(diǎn)。每一節(jié)點(diǎn)代表位于文件系統(tǒng)中的一個具體物理路徑,用來存儲數(shù)據(jù)。

圖片圖片

如上圖,節(jié)點(diǎn) count 位于/business/product/count 路徑,節(jié)點(diǎn) temp 可能存儲著數(shù)據(jù) 100,而節(jié)點(diǎn)/shop/order/1 可能存儲著類似{“id”:“1”,“itemName”:“Notebook”,“price”:“4000”}”這樣的復(fù)雜數(shù)據(jù)結(jié)構(gòu)和信息。ZooKeeper 中所有數(shù)據(jù)都是通過 ZNode 的路徑被引用的。

介紹完 ZooKeeper 的基本結(jié)構(gòu),我們來分析為什么它適合實(shí)現(xiàn)注冊中心。

事實(shí)上,在注冊中心的實(shí)現(xiàn)過程中,最復(fù)雜的就是變更通知機(jī)制,因?yàn)樗婕暗饺绾卧诜?wù)提供者實(shí)例狀態(tài)發(fā)生變更時,有效地通知到服務(wù)的消費(fèi)者,從而避免遠(yuǎn)程調(diào)用發(fā)生失敗。添加了通知機(jī)制的注冊中心模型是這樣的:

圖片圖片

我們知道狀態(tài)變更管理可以采用發(fā)布 - 訂閱模式,具體來說,服務(wù)提供者可以根據(jù)服務(wù)定義發(fā)布服務(wù),而服務(wù)消費(fèi)者則通過對自己感興趣的服務(wù)進(jìn)行訂閱,并獲取變更后的服務(wù)實(shí)例信息。

圖片圖片

上圖展示的就是一種服務(wù)監(jiān)聽機(jī)制。有了這一機(jī)制,服務(wù)提供者實(shí)例的狀態(tài)一旦發(fā)生變化,服務(wù)消費(fèi)者就能第一時間獲取變更通知,從而獲取最新的服務(wù)狀態(tài)。

那我們?nèi)绾蝸韺?shí)現(xiàn)這種監(jiān)聽機(jī)制呢?ZooKeeper 為我們提供了現(xiàn)成的解決方案,就是 Watcher 機(jī)制。這個 Watcher 機(jī)制就相當(dāng)于上圖中所展示的這種監(jiān)聽器。監(jiān)聽器通過對 ZNode 進(jìn)行監(jiān)聽,確保了節(jié)點(diǎn)信息發(fā)生變化時能夠?qū)崟r捕捉到這種變化并把它傳遞到客戶端,從而觸發(fā)客戶端的回調(diào)處理函數(shù)。

從實(shí)現(xiàn)上講,ZNode 是開發(fā)人員通過代碼操控的主要對象。對 ZNode 的基本操作包括創(chuàng)建節(jié)點(diǎn)、獲取子節(jié)點(diǎn)以及獲取和設(shè)置節(jié)點(diǎn)數(shù)據(jù)等。我們可以通過引入 ZooKeeper 的客戶端組件來實(shí)現(xiàn)這些操作,常見的客戶端包括自帶的 ZooKeeper API 和第三方 Curator 等。

ZooKeeper 中涉及的主要操作包含了以下 6 種:

圖片圖片

各種工具框架中對 ZooKeeper 的控制基本都是對這些操作的封裝和應(yīng)用。基于 ZooKeeper 各項(xiàng)功能特性實(shí)現(xiàn)注冊中心的基本思路如下圖:

圖片圖片

可以看到,無論是服務(wù)的提供者還是消費(fèi)者,在服務(wù)初始化時都會與 ZooKeeper 服務(wù)器建立連接。然后,圖中所展示的發(fā)布服務(wù)定義、注冊新服務(wù)、獲取和監(jiān)聽服務(wù)地址等操作本質(zhì)上都是對 ZNode 各種基本操作的封裝。當(dāng)然,作為 ZooKeeper 的客戶端,服務(wù)提供者和消費(fèi)者都需要與 ZooKeeper 保持心跳檢測。

Dubbo 框架默認(rèn)把 ZooKeeper 作為它的注冊中心實(shí)現(xiàn)工具。接下來就讓我們來看看 Dubbo 中的 ZooKeeper 注冊中心。

Dubbo 中的 ZooKeeper 注冊中心

對于 Dubbo 而言,我們首先需要明確保存在 ZNode 中的具體內(nèi)容,這就是服務(wù)提供者和消費(fèi)者的 URL 信息,它們會被分別保存在 ZooKeeper 的/providers 和/consumers 節(jié)點(diǎn)之下。

圖片圖片

同時,服務(wù)消費(fèi)者還會對/providers 節(jié)點(diǎn)進(jìn)行訂閱。這樣,消費(fèi)者就能實(shí)時獲取提供者的 URL 信息。顯然,這個時候我們會對/providers 節(jié)點(diǎn)添加 Watcher 機(jī)制。

我們進(jìn)一步分析這些注冊信息,可以看到,Dubbo 對各個節(jié)點(diǎn)進(jìn)行了合理編排,構(gòu)成了 Root、Service、Type、URL 這樣的服務(wù)地址分層結(jié)構(gòu)。

圖片圖片

Dubbo 通過對不同層級節(jié)點(diǎn)進(jìn)行注冊和訂閱,來實(shí)現(xiàn)服務(wù)地址的發(fā)布和推送。當(dāng)然,這種分層結(jié)構(gòu)對于我們?nèi)绾谓M織 ZooKeeper 中的數(shù)據(jù)有很好的借鑒意義。

接下來,讓我們來看一些 Dubbo 中的源碼。我們來看一下代表注冊中心的 ZookeeperRegistry 類,而 ZookeeperRegistry 中最重要的就是它的構(gòu)造函數(shù)。這是對應(yīng)的代碼:

public ZookeeperRegistry(URL url, ZookeeperTransporter, zookeeperTransporter) {
        ...
        //構(gòu)建 Zookeeper 客戶端
     zkClient = zookeeperTransporter.connect(url);
        //添加 Watcher
     zkClient.addStateListener(new StateListener() {
             public void stateChanged(int state) {
                 if (state == RECONNECTED) {
                     try {
                         recover();
                     } catch (Exception e) {
                         logger.error(e.getMessage(), e);
                     }
                 }
             }
         });
 }

不難看出,在 ZookeeperRegistry 的構(gòu)造函數(shù)中,我們通過 ZookeeperClient 客戶端工具創(chuàng)建了與服務(wù)器的連接,并且通過 addStateListener 方法添加了監(jiān)聽器。一旦連接發(fā)生重連,就會觸發(fā)回復(fù)操作。

為了更好地理解這段代碼,我們需要明確另外兩個核心對象的創(chuàng)建過程。這兩個核心對象分別是前面所展示的 ZookeeperTransporter 和 ZookeeperClient,其中 ZookeeperTransporter 根據(jù)傳入的 URL,通過創(chuàng)建與 Zookeeper 服務(wù)器的連接獲取一個 ZookeeperClient 對象,而 ZookeeperClient 則包含了注冊中心運(yùn)行過程中所有的數(shù)據(jù)操作。

圖片圖片

從功能定位上講,我們可以把 ZookeeperTransporter 看做是一種通信層組件,只負(fù)責(zé)與 ZooKeeper 實(shí)現(xiàn)網(wǎng)絡(luò)通信,而 ZookeeperClient 則封裝了所有的注冊中心操作方法,是一種業(yè)務(wù)層組件。Dubbo 在這里所采用的這種分層設(shè)計思想同樣值得我們借鑒。

目前可以與 ZooKeeper 服務(wù)器進(jìn)行交互的客戶端有很多,Dubbo 提供了對 Zkclient 和 Curator 這兩個客戶端工具的集成,對應(yīng)的 Transporter 和 ZookeeperClient 實(shí)現(xiàn)類如下所示:

圖片圖片

Dubbo 使用 Zkclient 作為其默認(rèn)實(shí)現(xiàn)。

接下來,我們終于到了分析注冊中心具體操作的時候了。ZookeeperRegistry 提供了 doRegister、doUnregister、doSubscribe 和 doUnsubscribe 方法,分別對應(yīng)注冊、取消注冊、訂閱和取消訂閱這四個具體操作。其中 doRegister 和 doUnregister 這兩個方法比較簡單,只是直接調(diào)用 Zkclient 的 create 和 delete 方法。而 doSubscribe 方法完成服務(wù)訂閱操作,代碼比較長,我們提取其中的核心代碼:

ChildListener zkListener = listeners.get(listener);
 if (zkListener == null) {
         listeners.putIfAbsent(listener, new ChildListener() {
                   public void childChanged(String parentPath, List<String>
 currentChilds) {
                        for (String child : currentChilds) {
                             child = URL.decode(child);
                             if (!anyServices.contains(child)) {
                                 anyServices.add(child);
                                     subscribe(url.setPath(child).addParameters(Constants.INTERFACE_KEY, child,Constants.CHECK_KEY, String.valueOf(false)), listener);
                            }
                       }
                   }
             });
         zkListener = listeners.get(listener);
 }

可以看到,Dubbo 會訂閱父級目錄,而當(dāng)有子節(jié)點(diǎn)發(fā)生變化時就會觸發(fā) ChildListener 中的回調(diào)函數(shù),這個回調(diào)函數(shù)會對這個路徑下的所有子節(jié)點(diǎn)執(zhí)行訂閱操作。

掌握了服務(wù)訂閱的實(shí)現(xiàn)過程,理解取消訂閱的原理就很簡單了,我們只要去掉 URL 上已經(jīng)注冊的監(jiān)聽器就可以了,doUnsubscribe 方法如下所示:

protected void doUnsubscribe(URL url, NotifyListener listener) {
  ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url);
         if (listeners != null) {
             ChildListener zkListener = listeners.get(listener);
             if (zkListener != null) {
                 zkClient.removeChildListener(toUrlPath(url), zkListener);
             }
         }
 }

至此,在 Dubbo 中,如何基于 ZooKeeper 實(shí)現(xiàn)注冊中心的實(shí)現(xiàn)過程就介紹完了。如果我們想要自己動手實(shí)現(xiàn)一個類似的注冊中心,那這個 Dubbo 中的實(shí)現(xiàn)過程還是具備很多參考價值的。

總結(jié)

我們來總結(jié)回顧一下這次講的內(nèi)容。我們針對微服務(wù)架構(gòu)中的一個核心技術(shù)組件,即注冊中心的基本模型做了展開,并基于 ZooKeeper 這款分布式協(xié)調(diào)工具重點(diǎn)分析了 Dubbo 中注冊中心的實(shí)現(xiàn)方式以及所具備的功能特性。

責(zé)任編輯:武曉燕 來源: 程序猿技術(shù)充電站
相關(guān)推薦

2025-01-16 00:20:41

2023-02-26 00:00:00

2023-01-30 22:43:39

DubboZooKeeper

2021-01-06 13:52:19

zookeeper開源分布式

2025-04-21 04:00:00

2020-01-10 10:58:34

ZooKeeperEureka注冊中心

2020-06-29 07:58:18

ZooKeeperConsul 注冊中心

2017-12-05 17:44:31

機(jī)器學(xué)習(xí)CNN卷積層

2020-10-14 08:50:38

搞懂 Netty 線程

2025-05-06 01:14:00

系統(tǒng)編程響應(yīng)式

2023-10-18 10:55:55

HashMap

2024-01-03 13:39:00

JS,Javascrip算法

2025-04-11 05:55:00

2025-01-13 16:00:00

服務(wù)網(wǎng)關(guān)分布式系統(tǒng)架構(gòu)

2023-01-05 07:55:59

Zookeeper服務(wù)注冊

2021-10-15 08:32:03

RocketMQ數(shù)據(jù)結(jié)構(gòu)架構(gòu)

2023-05-29 08:12:38

2021-10-09 19:05:06

channelGo原理

2021-10-11 11:58:41

Channel原理recvq

2025-03-17 00:21:00

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號