10、dubbo源碼分析 之 服務(wù)遠(yuǎn)程暴露(下)

在前面的文章我們分析了一下 dubbo 遠(yuǎn)程服務(wù)暴露過(guò)程中通過(guò) Netty 進(jìn)行 Socket 服務(wù)暴露。使得遠(yuǎn)程客戶端可以訪問(wèn)這個(gè)暴露的服務(wù),這個(gè)只是解決了訪問(wèn)之前點(diǎn)到點(diǎn)的服務(wù)調(diào)用。對(duì)于分步式環(huán)境當(dāng)中,越來(lái)越多的服務(wù)我們?nèi)绾喂芾聿⑶抑卫磉@些服務(wù)是一個(gè)問(wèn)題。因此 dubbo 引入了注冊(cè)中心這個(gè)概念,把服務(wù)暴露、服務(wù)調(diào)用的信息保存到注冊(cè)中心上面。并且還可以訂閱注冊(cè)中心,實(shí)現(xiàn)服務(wù)自動(dòng)發(fā)現(xiàn)。因?yàn)?dubbo 遠(yuǎn)程暴露里面的過(guò)程還是比較復(fù)雜的,所以我就分為三個(gè)文章來(lái)講解 dubbo 的遠(yuǎn)程暴露:

  • dubbo 遠(yuǎn)程暴露 – Netty 暴露服務(wù)
  • dubbo 遠(yuǎn)程暴露 – Zookeeper 連接
  • dubbo 遠(yuǎn)程暴露 – Zookeeper 注冊(cè) & 訂閱

在上篇文章中我們分析 dubbo 是如何創(chuàng)建 zookeeper 這個(gè)注冊(cè)中心的。下面我們就來(lái)分析一下 dubbo 究竟使用 zookeeper 這個(gè)組件來(lái)做了哪些事。

1、RegistryProtocol#export

下面就是 dubbo 暴露的核心步驟的代碼,可能由于版本的原因(下面的代碼基于 2.6.1)代碼會(huì)有所差異但是核心思想不變。

    public <T> Exporter<T> export(final Invoker<T> originInvoker) throws RpcException {
        //export invoker
        final ExporterChangeableWrapper<T> exporter = doLocalExport(originInvoker);

        URL registryUrl = getRegistryUrl(originInvoker);

        //registry provider
        final Registry registry = getRegistry(originInvoker);
        final URL registedProviderUrl = getRegistedProviderUrl(originInvoker);

        //to judge to delay publish whether or not
        boolean register = registedProviderUrl.getParameter("register", true);

        ProviderConsumerRegTable.registerProvider(originInvoker, registryUrl, registedProviderUrl);

        if (register) {
            register(registryUrl, registedProviderUrl);
            ProviderConsumerRegTable.getProviderWrapper(originInvoker).setReg(true);
        }

        // Subscribe the override data
        // FIXME When the provider subscribes, it will affect the scene : a certain JVM exposes the service and call the same service. Because the subscribed is cached key with the name of the service, it causes the subscription information to cover.
        final URL overrideSubscribeUrl = getSubscribedOverrideUrl(registedProviderUrl);
        final OverrideListener overrideSubscribeListener = new OverrideListener(overrideSubscribeUrl, originInvoker);
        overrideListeners.put(overrideSubscribeUrl, overrideSubscribeListener);
        registry.subscribe(overrideSubscribeUrl, overrideSubscribeListener);
        //Ensure that a new exporter instance is returned every time export
        return new DestroyableExporter<T>(exporter, originInvoker, overrideSubscribeUrl, registedProviderUrl);
    }

在之前的文章中分析了 dubbo 通過(guò) netty 暴露服務(wù),然后獲取到 zookeeper 注冊(cè)中心 --- ZookeeperRegistry。下面就是把 Provider (服務(wù)提供者)的信息注冊(cè)到注冊(cè)中心上。這樣 Consumer (服務(wù)消費(fèi)者)就可以通過(guò) Registry (注冊(cè)中心)獲取到 Provider 的信息。這樣就解耦了 Provider 與 Consumer,并且可以通過(guò) Registry 來(lái)修改路由規(guī)則、權(quán)重等控制。這樣就達(dá)到的服務(wù)的治理。下面我們就來(lái)講解一下,服務(wù)的注冊(cè)與訂閱。

2、ZookeeperRegistry#register

這個(gè)就是把服務(wù)信息注冊(cè)到 Zookeeper 上面去。

1、AbstractRegistry#register添加注冊(cè)Set<URL> registered(已注冊(cè)的URL),用于失敗重試。
2、ZookeeperRegistry#doRegister通過(guò)上篇 blog 講解的獲取到的 ZookeeperClient 把服務(wù)信息注冊(cè)到 Zookeeper 上。此時(shí)的 URL 為:

dubbo://192.168.75.1:20880/com.alibaba.dubbo.demo.DemoService?
anyhost=true&application=demo-provider&dubbo=2.0.0&generic=false&
interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=2076&
side=provider&timestamp=1522237459900

dubbo 會(huì)基于這個(gè) URL 生成一個(gè)新的URL,生成規(guī)則為:

"/dubbo/" + url里面的interface的值 + "/providers/" + URL.encode(url)

生成后的值 :

/dubbo/com.alibaba.dubbo.demo.DemoService/providers/
dubbo%3A%2F%2F192.168.75.1%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26dubbo%3D2.0.0%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D2076%26side%3Dprovider%26timestamp%3D1522237459900

然后在 Zookeeper 上面把 /dubbo/com.alibaba.dubbo.demo.DemoService/providers/ 創(chuàng)建成持久化節(jié)點(diǎn),而后面部分的 URL 就會(huì)創(chuàng)建成臨時(shí)節(jié)點(diǎn)。

把服務(wù)提供者信息創(chuàng)建成臨時(shí)節(jié)點(diǎn)的好處就是如果當(dāng)前服務(wù)掛掉,這個(gè)節(jié)點(diǎn)就會(huì)自動(dòng)刪除。這樣失效服務(wù)就可以自動(dòng)剔除。

Zookeeper 持久化節(jié)點(diǎn) 和臨時(shí)節(jié)點(diǎn)有什么區(qū)別?
持久化節(jié)點(diǎn):一旦被創(chuàng)建,觸發(fā)主動(dòng)刪除掉,否則就一直存儲(chǔ)在ZK里面。
臨時(shí)節(jié)點(diǎn):與客戶端會(huì)話綁定,一旦客戶端會(huì)話失效,這個(gè)客戶端端所創(chuàng)建的所有臨時(shí)節(jié)點(diǎn)都會(huì)被刪除。

3、ZookeeperRegistry#subscribe

通過(guò)訂閱 Zookeeper 上面的的節(jié)點(diǎn)信息變更, 可以通過(guò) dubbo-admin來(lái)修改服務(wù)路由規(guī)則、權(quán)重等。

1、創(chuàng)建一個(gè) NotifyListener 實(shí)例 OverrideListener, 當(dāng)收到服務(wù)變更通知時(shí)觸發(fā)。
2、在 Zookeeper 注冊(cè)中心創(chuàng)建持久化節(jié)點(diǎn)/dubbo/com.alibaba.dubbo.demo.DemoService/configurators,用于接收 dubbo-admin這個(gè)客戶端上對(duì)于集群的服務(wù)治理。

ZookeeperRegistry#doSubscribe {
    zkClient.create(path, false)
}

3、啟動(dòng)加入訂閱/dubbo/com.alibaba.dubbo.demo.DemoService/configurators,如果該節(jié)點(diǎn)信息發(fā)生改變,就會(huì)交給FailbackRegistry.notify處理。

ZookeeperRegistry#doSubscribe {
    zkClient.addChildListener(path, zkListener)
}

4、FailbackRegistry#notify

1、把服務(wù)端的注冊(cè) url 信息更新到本地緩存(AbstractRegistry#saveProperties),以Window為例:

C:\Users\Carl\.dubbo\dubbo-registry-10.65.209.12.cache

2、調(diào)用傳入的OverrideListener#notify,如果修改了 URL 信息,調(diào)用RegistryProtocol.this.doChangeLocalExport(originInvoker, newUrl)重新暴露當(dāng)前服務(wù)。

前面二篇加上這一篇就是 dubbo 遠(yuǎn)程服務(wù)暴露的整個(gè)過(guò)程。下面這張圖片就是 dubbo 進(jìn)行服務(wù)暴露、服務(wù)遠(yuǎn)程調(diào)用添加 dubbo monitor 后 Zookeeper 上面 dubbo 節(jié)點(diǎn)的結(jié)構(gòu)圖。

這里寫圖片描述

關(guān)于zookeeper在Dubbo中扮演了一個(gè)什么角色,起到了什么作用啊?,大家可以看一下這篇知乎上面的問(wèn)答。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 在上一篇文章我們講解了一下 dubbo 服務(wù)暴露過(guò)程中的本地暴露。它只是一個(gè)開胃小菜,主要是為我們后面講解遠(yuǎn)程暴露...
    carl_zhao閱讀 354評(píng)論 0 1
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,908評(píng)論 18 139
  • 暴露服務(wù)的過(guò)程中,會(huì)涉及到兩個(gè)Protocol DubboProtocol主要是做網(wǎng)絡(luò)通信相關(guān)初始化 Regist...
    _六道木閱讀 593評(píng)論 0 0
  • 在上一篇文章我們講解了一下 dubbo 遠(yuǎn)程服務(wù)暴露過(guò)程中通過(guò) Netty 進(jìn)行 Socket 服務(wù)暴露。使得遠(yuǎn)程...
    carl_zhao閱讀 342評(píng)論 0 0
  • 一、什么是基本面? 指對(duì)宏觀經(jīng)濟(jì)面、公司主營(yíng)業(yè)務(wù)所處行業(yè)、公司業(yè)務(wù)同行業(yè)競(jìng)爭(zhēng)水平和公司內(nèi)部管理水平包括對(duì)管理層的考...
    大森森_閱讀 420評(píng)論 0 0