欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

Dubbo如何實(shí)現(xiàn)服務(wù)的動(dòng)態(tài)發(fā)現(xiàn)

這篇文章主要介紹“Dubbo如何實(shí)現(xiàn)服務(wù)的動(dòng)態(tài)發(fā)現(xiàn)”,在日常操作中,相信很多人在Dubbo如何實(shí)現(xiàn)服務(wù)的動(dòng)態(tài)發(fā)現(xiàn)問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”Dubbo如何實(shí)現(xiàn)服務(wù)的動(dòng)態(tài)發(fā)現(xiàn)”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

成都創(chuàng)新互聯(lián)公司專注于企業(yè)全網(wǎng)營(yíng)銷推廣、網(wǎng)站重做改版、濱城網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5建站、商城網(wǎng)站建設(shè)、集團(tuán)公司官網(wǎng)建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)公司、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為濱城等各大城市提供網(wǎng)站開(kāi)發(fā)制作服務(wù)。

ps: 以下將 ZooKeeper 縮寫(xiě)為 zk。

一、dubbo zk 數(shù)據(jù)結(jié)構(gòu)

在 ZooKeeper 基本概念分享一文講道,ZK 內(nèi)部是一種樹(shù)形層次結(jié)構(gòu),節(jié)點(diǎn)存在多種類型。而 Dubbo 只會(huì)創(chuàng)建持久節(jié)點(diǎn)和臨時(shí)節(jié)點(diǎn)。

若服務(wù)提供者服務(wù)接口為 com.service.FooService,將會(huì)在 ZK 中創(chuàng)建創(chuàng)建如下路徑 /dubbo/com.service.FooService/providers/providerURL。

服務(wù)路徑分為四層,根節(jié)點(diǎn)默認(rèn)為 dubbo,可以在 dubbo-registry 設(shè)置 group 屬性改變?cè)撝怠?/p>

ps: 若無(wú)注冊(cè)中心隔離需求,不要隨便修改。

第二層節(jié)點(diǎn)為服務(wù)節(jié)點(diǎn)全名稱,如 com.service.FooService。

第三層節(jié)點(diǎn)為服務(wù)目錄,如 providers。另外還存在其他目錄節(jié)點(diǎn),分別為 consumers(消費(fèi)者目錄),configurators(配置目錄),routers(路由目錄)。下面服務(wù)訂閱主要針對(duì)這一層節(jié)點(diǎn)。

第四個(gè)節(jié)點(diǎn)為具體服務(wù)節(jié)點(diǎn),節(jié)點(diǎn)名為具體的 URL 字符串,如 dubbo://2.0.1.13:12345/com.dubbo.example.DemoService?xx=xx ,該節(jié)點(diǎn)默認(rèn)為臨時(shí)節(jié)點(diǎn)。 dubbo ZK 樹(shù)形內(nèi)部結(jié)構(gòu)示例為:

Dubbo如何實(shí)現(xiàn)服務(wù)的動(dòng)態(tài)發(fā)現(xiàn)

ZK 內(nèi)部服務(wù)具體示例如下:

Dubbo如何實(shí)現(xiàn)服務(wù)的動(dòng)態(tài)發(fā)現(xiàn)

二、RegistryFactory 實(shí)現(xiàn)

Dubbo 可以在配置文件中指定使用注冊(cè)中心,可以使用 dubbo.registry.protocol 指定具體注冊(cè)中心類型,也可以設(shè)置 dubbo.registry.address 指定。注冊(cè)中心相關(guān)實(shí)現(xiàn)將會(huì)使用 RegistryFactory 工廠類創(chuàng)建。

RegistryFactory 接口源碼如下:

@SPI("dubbo")
public interface RegistryFactory {
    @Adaptive({"protocol"})
    Registry getRegistry(URL url);
}

RegistryFactory 接口方法使用 @Adaptive 注解,這里將會(huì)使用 Dubbo SPI 機(jī)制,自動(dòng)生成代碼的一些實(shí)現(xiàn)邏輯。這里將會(huì)根據(jù) URL 中 protocol 屬性,去調(diào)用最終實(shí)現(xiàn)子類。

RegistryFactory 實(shí)現(xiàn)子類如圖所示:

Dubbo如何實(shí)現(xiàn)服務(wù)的動(dòng)態(tài)發(fā)現(xiàn)

AbstractRegistryFactory 將會(huì)實(shí)現(xiàn)接口的 getRegistry 方法,主要完成加鎖,并調(diào)用抽象模板方法 createRegistry 創(chuàng)建具體注冊(cè)中心實(shí)現(xiàn)類,并將其緩存在內(nèi)存中。

AbstractRegistryFactory#getRegistry 源碼如下所示:

    public Registry getRegistry(URL url) {
        url = URLBuilder.from(url)
                .setPath(RegistryService.class.getName())
                .addParameter(Constants.INTERFACE_KEY, RegistryService.class.getName())
                .removeParameters(Constants.EXPORT_KEY, Constants.REFER_KEY)
                .build();
        String key = url.toServiceStringWithoutResolving();
        // 加鎖,防止并發(fā)
        LOCK.lock();
        try {
	    // 先從緩存中取
            Registry registry = REGISTRIES.get(key);
            if (registry != null) {
                return registry;
            }
            //使用 Dubbo SPI 進(jìn)制創(chuàng)建
            registry = createRegistry(url);
            if (registry == null) {
                throw new IllegalStateException("Can not create registry " + url);
            }
	    // 放入緩存
            REGISTRIES.put(key, registry);
            return registry;
        } finally {
            // Release the lock
            LOCK.unlock();
        }
    }

注冊(cè)中心實(shí)例將會(huì)通過(guò)具體工廠類創(chuàng)建,這里我們看下 ZookeeperRegistryFactory 源碼:

public class ZookeeperRegistryFactory extends AbstractRegistryFactory {

    private ZookeeperTransporter zookeeperTransporter;

    /**
     * 通過(guò) Dubbo SPI 進(jìn)制注入
     * @param zookeeperTransporter
     */
    public void setZookeeperTransporter(ZookeeperTransporter zookeeperTransporter) {
        this.zookeeperTransporter = zookeeperTransporter;
    }

    @Override
    public Registry createRegistry(URL url) {
        return new ZookeeperRegistry(url, zookeeperTransporter);
    }

}

ps:Dubbo SPI 機(jī)制還具有 IOC 特性,這里的ZookeeperTransporter 注入可以參考:Dubbo 擴(kuò)展點(diǎn)加載

三、zk 模塊源碼解析

講完注冊(cè)中心實(shí)例創(chuàng)建過(guò)程,下面深入 ZookeeperRegistry 實(shí)現(xiàn)源碼。

ZookeeperRegistry 繼承 FailbackRegistry抽象類,所以其需要實(shí)現(xiàn)其父類抽象模板方法,下面主要了解 doRegisterdoSubscribe源碼 。

3.1 doRegister

服務(wù)提供者需要將服務(wù)注冊(cè)到注冊(cè)中心,注冊(cè)的目的是為了讓消費(fèi)者感知到服務(wù)的存在,從而發(fā)起遠(yuǎn)程調(diào)用,另一方面也讓服務(wù)治理中心感知新的服務(wù)提供者上線。zk 模塊服務(wù)注冊(cè)代碼比較簡(jiǎn)單,直接使用 zk 客戶端在注冊(cè)中心創(chuàng)建節(jié)點(diǎn)。

ZookeeperRegistry#doRegister 實(shí)現(xiàn)源碼如下:

    public void doRegister(URL url) {
        try {
            zkClient.create(toUrlPath(url), url.getParameter(Constants.DYNAMIC_KEY, true));
        } catch (Throwable e) {
            throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    }

zkClient.create 方法需要傳入兩個(gè)參數(shù)。

void create(String path, boolean ephemeral);

第一個(gè)參數(shù)為節(jié)點(diǎn)路徑,將會(huì)通過(guò) toUrlPath 將 URL 實(shí)例轉(zhuǎn)化成 ZK 中路徑格式,轉(zhuǎn)化結(jié)果如下:

## 轉(zhuǎn)化前 URL 如下:

dubbo://10.20.82.31:12345/com.dubbo.example.DemoService

## 調(diào)用  `toUrlPath`  轉(zhuǎn)換之后
/dubbo/com.dubbo.example.DemoService/providers/dubbo%3A%2F%2F10.20.82.31%3A12345%2Fcom.dubbo.example.DemoService

第二個(gè)參數(shù)主要決定 ZK 節(jié)點(diǎn)類型主要取自 URL 實(shí)例對(duì)象中 dynamic 參數(shù)值,若不存在,默認(rèn)為 true,也就是默認(rèn)將會(huì)創(chuàng)建臨時(shí)節(jié)點(diǎn)。

zkClient.create 方法里將會(huì)遞歸調(diào)用,首先父節(jié)點(diǎn)是否存在,不存在就會(huì)創(chuàng)建,直到最后一個(gè)節(jié)點(diǎn)跳出遞歸方法。

    public void create(String path, boolean ephemeral) {
	// 創(chuàng)建永久節(jié)點(diǎn)之前需要判斷是否已存在
        if (!ephemeral) {
            if (checkExists(path)) {
                return;
            }
        }
	// 判斷是否存在父節(jié)點(diǎn)
        int i = path.lastIndexOf('/');
        if (i > 0) {
	   // 遞歸創(chuàng)建父節(jié)點(diǎn)
            create(path.substring(0, i), false);
        }
        if (ephemeral) {
	    // 創(chuàng)建臨時(shí)節(jié)點(diǎn)
            createEphemeral(path);
        } else {
	   // 創(chuàng)建永久節(jié)點(diǎn)
            createPersistent(path);
        }
    }

最后 createEphemeralcreatePersistent 實(shí)際創(chuàng)建節(jié)點(diǎn)操作將會(huì)交給 ZK 客戶端類,這里實(shí)現(xiàn)比較簡(jiǎn)單,可以自行參考源碼。

ps: dubbo 在 2.6.1 起將 zk 客戶端默認(rèn)使用 Curator,之前版本使用 zkclient。dubbo 2.7.1 開(kāi)始去除 zkclient 實(shí)現(xiàn),也就是說(shuō)只能使用 Curator 。

3.2 為何 dubbo 服務(wù)提供者節(jié)點(diǎn)使用 zk 臨時(shí)節(jié)點(diǎn)

zk 臨時(shí)節(jié)點(diǎn)將會(huì)在 zk 客戶端斷開(kāi)后,自動(dòng)刪除。dubbo 服務(wù)提供者正常下線,其會(huì)主動(dòng)刪除 zk 服務(wù)節(jié)點(diǎn)。

如果服務(wù)異常宕機(jī),zk 服務(wù)節(jié)點(diǎn)就不能正常刪除,這就導(dǎo)致失效的服務(wù)一直存在 ZK 上,消費(fèi)者還會(huì)調(diào)用該失效節(jié)點(diǎn),導(dǎo)致消費(fèi)者報(bào)錯(cuò)。通過(guò) zk 臨時(shí)節(jié)點(diǎn)特性,讓 zk 服務(wù)端主動(dòng)刪除失效節(jié)點(diǎn),從而下線失效服務(wù)。

四、doSubscribe: 服務(wù)動(dòng)態(tài)發(fā)現(xiàn)的原理

4.1 訂閱基本原理

服務(wù)訂閱通常有 pull 和 push 兩種方式。pull 模式需要客戶端定時(shí)向注冊(cè)中心拉取配置,而 push 模式采用注冊(cè)中心主動(dòng)推送數(shù)據(jù)給客戶端。

dubbo zk 注冊(cè)中心采用是事件通知與客戶端拉取方式。服務(wù)第一次訂閱的時(shí)候?qū)?huì)拉取對(duì)應(yīng)目錄下全量數(shù)據(jù),然后在訂閱的節(jié)點(diǎn)注冊(cè)一個(gè) watcher。一旦目錄節(jié)點(diǎn)下發(fā)生任何數(shù)據(jù)變化,zk 將會(huì)通過(guò) watcher 通知客戶端??蛻舳私拥酵ㄖ?,將會(huì)重新拉取該目錄下全量數(shù)據(jù),并重新注冊(cè) watcher。利用這個(gè)模式,dubbo 服務(wù)就可以就做到服務(wù)的動(dòng)態(tài)發(fā)現(xiàn)。

4.2 源碼解析

講完訂閱的基本原理,接著深入源碼。

doSubscribe 方法需要傳入兩個(gè)參數(shù),一個(gè)為 URL 實(shí)例,另一個(gè)為 NotifyListener,變更事件的監(jiān)聽(tīng)器。 方法內(nèi)部會(huì)根據(jù) URL 接口類型分成兩部分邏輯,全量訂閱服務(wù)與部分類別訂閱服務(wù)。

doSubscribe 方法整體源碼邏輯:

    public void doSubscribe(final URL url, final NotifyListener listener) {
        if (Constants.ANY_VALUE.equals(url.getServiceInterface())) {
		// 全量訂閱邏輯
        } else {
		// 部分類別訂閱邏輯
        }
    }

服務(wù)治理中心(dubbo-admin),需要訂閱 service 全量接口,用以感知每個(gè)服務(wù)的狀態(tài),所以訂閱之前將會(huì)把 service 設(shè)置成 *,處理所有service。

服務(wù)消費(fèi)者或服務(wù)提供者將會(huì)走部分類別訂閱服務(wù),下面我們以消費(fèi)者視角,深入后續(xù)源碼。

文章剛開(kāi)頭講道了 zk 目錄節(jié)點(diǎn)存在四種類型,這里將會(huì)根據(jù) 根據(jù) URL 中 category值,決定訂閱節(jié)點(diǎn)路徑。

服務(wù)提供者 URL 中 category值默認(rèn)為 configurators,而消費(fèi)者 URL 中category值默認(rèn)為 providers,configurators,routers。如果 category類別值為 *,將會(huì)訂閱四種類別路徑,否則將會(huì)只訂閱 providers類型的路徑。

toCategoriesPath 源碼如下:

    private String[] toCategoriesPath(URL url) {
        String[] categories;
	// 如果類別為 *,訂閱四種類型的全量數(shù)據(jù)
        if (Constants.ANY_VALUE.equals(url.getParameter(Constants.CATEGORY_KEY))) {
            categories = new String[]{Constants.PROVIDERS_CATEGORY, Constants.CONSUMERS_CATEGORY,
                    Constants.ROUTERS_CATEGORY, Constants.CONFIGURATORS_CATEGORY};
        } else {
            categories = url.getParameter(Constants.CATEGORY_KEY, new String[]{Constants.DEFAULT_CATEGORY});
        }
	// 返回路徑數(shù)組
        String[] paths = new String[categories.length];
        for (int i = 0; i < categories.length; i++) {
            paths[i] = toServicePath(url) + Constants.PATH_SEPARATOR + categories[i];
        }
        return paths;
    }

接著循環(huán)路徑數(shù)組,循環(huán)內(nèi)將會(huì)緩存節(jié)點(diǎn)監(jiān)聽(tīng)器,用以提高性能。

    // 循環(huán)路徑數(shù)組
    for (String path : toCategoriesPath(url)) {
        ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url);
        // listeners  緩存為空,創(chuàng)建緩存
        if (listeners == null) {
            zkListeners.putIfAbsent(url, new ConcurrentHashMap<>());
            listeners = zkListeners.get(url);
        }
        ChildListener zkListener = listeners.get(listener);
        // zkListener  緩存為空則創(chuàng)建緩存
        if (zkListener == null) {
            listeners.putIfAbsent(listener, (parentPath, currentChilds) -> ZookeeperRegistry.this.notify(url, listener, toUrlsWithEmpty(url, parentPath, currentChilds)));
            zkListener = listeners.get(listener);
        }
        // 創(chuàng)建訂閱節(jié)點(diǎn)
        zkClient.create(path, false);
        // 使用 ZK 客戶端訂閱節(jié)點(diǎn)
        List<String> children = zkClient.addChildListener(path, zkListener);
        if (children != null) {
            // 存儲(chǔ)全量需要通知的 URL
            urls.addAll(toUrlsWithEmpty(url, path, children));
        }
    }
    // 回調(diào) NotifyListener
    notify(url, listener, urls);

最終將會(huì)使用 CuratorClient.getChildren().usingWatcher(listener).forPath(path) 在 ZK 節(jié)點(diǎn)注冊(cè) watcher,并獲取目錄節(jié)點(diǎn)下所有子節(jié)點(diǎn)數(shù)據(jù)。

這里 watcher 使用 Curator 接口 CuratorWatcher,一旦 ZK 節(jié)點(diǎn)發(fā)生會(huì)變化,將會(huì)回調(diào) CuratorWatcher#process 方法。

CuratorWatcher#process 方法源碼如下:

        public void process(WatchedEvent event) throws Exception {
            if (childListener != null) {
                String path = event.getPath() == null ? "" : event.getPath();
                childListener.childChanged(path,
                       // 重新設(shè)置 watcher,并獲取節(jié)點(diǎn)下所有子節(jié)點(diǎn)
                        StringUtils.isNotEmpty(path)
                                ? client.getChildren().usingWatcher(this).forPath(path)
                                : Collections.<String>emptyList());
            }
        }

消費(fèi)者訂閱時(shí)序圖如下:

Dubbo如何實(shí)現(xiàn)服務(wù)的動(dòng)態(tài)發(fā)現(xiàn)

4.3 listener 關(guān)系圖

訂閱方法中我們碰到了多個(gè) listener類,剛開(kāi)始理解時(shí)候可能有點(diǎn)亂??梢詤⒖枷旅骊P(guān)系圖理清楚這其中的關(guān)系。

listener 關(guān)系圖如下:

Dubbo如何實(shí)現(xiàn)服務(wù)的動(dòng)態(tài)發(fā)現(xiàn)

回調(diào)關(guān)系如圖所示:

Dubbo如何實(shí)現(xiàn)服務(wù)的動(dòng)態(tài)發(fā)現(xiàn)

4.4 ZK 模塊訂閱存在問(wèn)題

ZK 第一次訂閱將會(huì)獲得目錄節(jié)點(diǎn)下所有子節(jié)點(diǎn),后續(xù)任意子節(jié)點(diǎn)變更,將會(huì)通過(guò) watcher 進(jìn)制回調(diào)通知。回調(diào)通知將會(huì)再次全量拉取節(jié)點(diǎn)目錄下所有子節(jié)點(diǎn)。這樣全量拉取將會(huì)有個(gè)局限,當(dāng)服務(wù)節(jié)點(diǎn)較多時(shí)將會(huì)對(duì)網(wǎng)絡(luò)造成很大的壓力。

Dubbo 2.7 之后版本引入元數(shù)據(jù)中心解決該問(wèn)題,詳情可參考,阿里技術(shù)專家詳解 Dubbo 實(shí)踐,演進(jìn)及未來(lái)規(guī)劃。

引用文中一種解決方案如下圖:

Dubbo如何實(shí)現(xiàn)服務(wù)的動(dòng)態(tài)發(fā)現(xiàn)

Dubbo如何實(shí)現(xiàn)服務(wù)的動(dòng)態(tài)發(fā)現(xiàn)

到此,關(guān)于“Dubbo如何實(shí)現(xiàn)服務(wù)的動(dòng)態(tài)發(fā)現(xiàn)”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

網(wǎng)站名稱:Dubbo如何實(shí)現(xiàn)服務(wù)的動(dòng)態(tài)發(fā)現(xiàn)
轉(zhuǎn)載注明:http://aaarwkj.com/article46/gpjjhg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)建站、移動(dòng)網(wǎng)站建設(shè)動(dòng)態(tài)網(wǎng)站、做網(wǎng)站、標(biāo)簽優(yōu)化網(wǎng)站設(shè)計(jì)公司

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

營(yíng)銷型網(wǎng)站建設(shè)
国产欧美激情一区二区| 亚洲一区乱码精品中文| 日韩在线欧美在线一区二区| 国产亚洲精品精品国产亚洲| 五月婷婷六月丁香在线观看| 亚洲成人日韩成人av| 午夜精品久久福利视频| 久久99久久久国产精品| 日韩不卡免费在线视频| 亚洲国产一区二区精品| 久久综合给合综合久久| 久久精品欧美日韩视频| 片子免费毛片日韩不卡一区| 日韩欧美精品一区二区三区四区| 久久精品一品二品三品| 欧美十八一区二区三区| 成人黄色动作片在线观看| 最新免费观看男女啪啪视频| 日本a亚洲中文字幕永远| 欧美日韩亚洲精品一区二区三区| 观看女性真实高潮的合集| 国产男女猛烈无遮挡网站| av熟妇人妻一区二区三区| 99久久精品国产熟女拳交| 亚洲精品网站国产高清| 日本精品视频一区二区三区| 国产一级特黄大片特爽| 丰满的少妇一区二区三区免费观看 | 亚洲精品国产熟女av| 国产一级成人免费视频| 国产成人久久精品二区三区| 国产自愉自愉免费精品七| 成人一区二区三区乱码| 青青草原三区在线播放| 国产一级黄色片免费看| 日韩最新人妻在线不卡| 久久99精品久久久国产| 国产91高清在线观看| 成年人片免费在线观看| 欧美日韩精品国产精品| 日韩欧美午夜福利在线视频|