12. Dubbo原理解析-註冊中心之基於dubbo協議的簡單註冊中心實現

基於dubbo協議開源只是給出了默認一個註冊中心實現SimpleRegistryService, 它只是一個簡單實現,不支持集羣,就是利用Map<String/*ip:port*/, Map<String/*service*/, URL>來存儲服務地址, 具體不在囉嗦了,請讀者翻看源代碼,可作爲自定義註冊中的參考。

註冊中心啓動

SimpleRegistryService本身也是作爲一個dubbo服務暴露。

<dubbo:protocolport="9090" />

<dubbo:service interface="com.alibaba.dubbo.registry.RegistryService"ref="registryService" registry="N/A" ondisconnect="disconnect"callbacks="1000">

     <dubbo:methodname="subscribe"><dubbo:argument index="1" callback="true"/></dubbo:method>

     <dubbo:methodname="unsubscribe"><dubbo:argument index="1" callback="false"/></dubbo:method>

</dubbo:service>

<bean id="registryService"class="com.alibaba.dubbo.registry.simple.SimpleRegistryService" />

上面是暴露註冊中心的dubbo服務配置,

定義了註冊中心服務的端口號

發佈RegistryService服務, registry屬性是”N/A”代表不能獲取註冊中心,註冊中心服務的發佈也是一個普通的dubbo服務的發佈,如果沒有配置這個屬性它也會尋找註冊中心,去通過註冊中心發佈,因爲自己本身就是註冊中心,直接對外發布服務,外部通過ip:port直接使用。

服務發佈定義了回調接口, 這裏定義了subscribe的第二個入參類暴露的回調服務供註冊中心回調,用來當註冊的服務狀態變更時反向推送到客戶端。

 

Dubbo協議的註冊中心的暴露以及調用過程過程跟普通的dubbo服務的其實是一樣的,可能跟絕大多數服務的不同的是在SimpleRegistryService在被接收訂閱請求subscribe的時候,同時會refer引用調用方暴露的NotifyListener服務,當有註冊數據變更時自動推送

  

生產者發佈服務

Dubbo協議向註冊中心發佈服務:當服務提供方,向dubbo協議的註冊中心發佈服務的時候,是如何獲取,創建註冊中心的,如何註冊以及訂閱服務的,下面我們來分析其流程。

看如下配置發佈服務:

<dubbo:registry protocol=”dubbo” address="127.0.0.1:9090" />

<beanid="demoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl"/>

<dubbo:serviceinterface="com.alibaba.dubbo.demo.DemoService" ref="demoService"/>

1. 指定了哪種的註冊中心,是基於dubbo協議的,指定了註冊中心的地址以及端口號

2. 發佈DemoService服務,服務的實現爲DemoServiceImpl

 

每個<dubbo:service/>在spring內部都會生成一個ServiceBean實例,ServiceBean的實例化過程中調用export方法來暴露服務

1. 通過loadRegistries獲取註冊中心registryUrls

registry://127.0.0.1:9090/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.5.4-SNAPSHOT&owner=william&pid=7084&registry=dubbo&timestamp=1415711791506

用統一數據模型URL表示:

protocol=registry表示一個註冊中心url

註冊中心地址127.0.0.1:9090

調用註冊中心的服務RegistryService

註冊中心協議是registry=dubbo

。。。。。。

2. 構建發佈服務的URL

dubbo://192.168.0.102:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.5.4-SNAPSHOT&generic=false&interface=com.alibaba.dubbo.demo.DemoService&loadbalance=roundrobin&methods=sayHello&owner=william&pid=7084&side=provider&timestamp=1415712331601

發佈協議protocol =dubbo

服務提供者的地址爲192.168.0.102:20880

發佈的服務爲com.alibaba.dubbo.demo.DemoService

。。。。。。

3. 遍歷registryUrls向註冊中心註冊服務

給每個registryUrl添加屬性key爲export,value爲上面的發佈服務url得到如下registryUrl

registry://127.0.0.1:9098/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.5.4-SNAPSHOT&export=dubbo%3A%2F%2F192.168.0.102%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26dubbo%3D2.5.4-SNAPSHOT%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26loadbalance%3Droundrobin%26methods%3DsayHello%26owner%3Dwilliam%26pid%3D7084%26side%3Dprovider%26timestamp%3D1415712331601&owner=william&pid=7084&registry=dubbo&timestamp=1415711791506

4. 由發佈的服務實例,服務接口以及registryUrl爲參數,通過代理工廠proxyFactory獲取Invoker對象,Invoker對象是dubbo的核心模型,其他對象都向它靠攏或者轉換成它。

5. 通過Protocol對象暴露服務protocol.export(invoker)

通過DubboProtocol暴露服務的監聽(不是此節內容)

通過RegistryProtocol將服務地址發佈到註冊中心,並訂閱此服務

 

RegistryProtocol.export(Invoker)暴露服務

1. 調DubboProtocol暴露服務的監聽

2. 獲取註冊中心getRegistry(Invoker)

URL轉換, 由Invoker獲取的url是registryURL它的協議屬性用來選擇何種的Protocol實例如RegistryProtocol, DubboProtocol或者RedisProtocol等等。 這裏要通過URL去選擇何種註冊中心,所以根據registry=dubbo屬性,重新設置url的協議屬性得registryUrl

dubbo://127.0.0.1:9098/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&dubbo=2.5.4-SNAPSHOT&export=dubbo%3A%2F%2F192.168.0.102%3A20880%2Fcom.alibaba.dubbo.demo.DemoService%3Fanyhost%3Dtrue%26application%3Ddemo-provider%26dubbo%3D2.5.4-SNAPSHOT%26generic%3Dfalse%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26loadbalance%3Droundrobin%26methods%3DsayHello%26owner%3Dwilliam%26pid%3D5040%26side%3Dprovider%26timestamp%3D1415715706560&owner=william&pid=5040&timestamp=1415715706529

RegistryFactory.getRegistry(url) 通過工廠類創建註冊中心,RegistryFactory通過dubbo的spi機制獲取對應的工廠類, 這裏的是基於dubbo協議的註冊中心,所以是DubboRegistryFactory

3. 獲取發佈url 就是registryUrl的export參數的值

registryProviderUrl=dubbo://10.33.37.7:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.5.4-SNAPSHOT&generic=false&interface=com.alibaba.dubbo.demo.DemoService&loadbalance=roundrobin&methods=sayHello&owner=william&pid=6976&side=provider&timestamp=1415846958825

4. DubboRegistry.register(registryProviderUrl)

通過註冊器向註冊中心註冊服務

這裏注意registryProviderUrl的並沒有設置category屬性, 在註冊中心UrlUtils.ismatch(conuumerUrl, providerUrl)比較的時候,providerUrl的category屬性取默認值providers,

這點消費者訂閱的時候會指定訂閱的url的category=providers,去判斷有沒有註冊的提供者。

5. 構建訂閱服務overrideProviderUrl,我們是發佈服務

provider://10.33.37.7:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&category=configurators&check=false&dubbo=2.5.4-SNAPSHOT&generic=false&interface=com.alibaba.dubbo.demo.DemoService&loadbalance=roundrobin&methods=sayHello&owner=william&pid=6432&side=provider&timestamp=1415847417663

6. 構建OverrideListener它實現與NotifyLisener,當註冊中心的訂閱的url發生變化時回調重新export

7. registry.subscribe(overrideProviderUrl, OverrideListener), 註冊器向註冊中心訂閱overrideProviderUrl,同時將Override Listener暴露爲回調服務,當註冊中心的overrideProviderUrl數據發生變化時回調,

註冊器DubboRegistry的registry,subscribe, unRegistry, unSubscribe都類似, 是一個dubbo的遠程服務調用


DubboRegistryFactory創建註冊中心過程

1. 根據傳入registryUrl重新構建

移除EXPORT_KEY REFER_KEY

添加訂閱回調參數

dubbo://127.0.0.1:9098/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&callbacks=10000&connect.timeout=10000&dubbo=2.5.4-SNAPSHOT&interface=com.alibaba.dubbo.registry.RegistryService&lazy=true&methods=register,subscribe,unregister,unsubscribe,lookup&owner=william&pid=8492&reconnect=false&sticky=true&subscribe.1.callback=true&timeout=10000&timestamp=1415783872554&unsubscribe.1.callback=false

2. 根據url 註冊服務接口構建註冊目錄對象RegistryDircectory,實現了NotiyfLisener,這裏NotiyfLisener實現主要是根據urls去refer引用遠程服務RegistryService得到對應的Invoker,當urls變化時重新refer;目錄服務可以列出所有可以執行的Invoker

3. 利用cluster的join方法,將Dirctory的多個Invoker對象僞裝成一個Invoker對象, 這裏默認集羣策略得到FailoverClusterInvoker

4. FailoverClusterInvoker利用ProxyFactory獲取到RegistryService服務的代理對象

5. 由RegistryService服務的代理對象和FailoverClusterInvoker構建dubbo協議的註冊中心註冊器DubboRegistry

6. RegistryDircectory設置註冊器DubboRegistry,設置dubbo的協議

7. 調用 RegistryDircectory的notify(urls)方法

主要是根據registryUrls, 引用各個註冊中心的RegistryService服務實現,將引用的服務按key=menthodName/value=invoker緩存起來, 目錄服務Directory.list(Invocation)會列出所調用方法的所有Invoker , 一個Invoker代表對一個註冊中心的調用實體。

8. 訂閱註冊中心服務, 服務的提供者調註冊中心的服務RegistryService屬於消費方, 所以訂閱服務的url的協議是consumer

consumer://192.168.0.102/com.alibaba.dubbo.registry.RegistryService?application=demo-provider&callbacks=10000&connect.timeout=10000&dubbo=2.5.4-SNAPSHOT&interface=com.alibaba.dubbo.registry.RegistryService&lazy=true&methods=register,subscribe,unregister,unsubscribe,lookup&owner=william&pid=6960&reconnect=false&sticky=true&subscribe.1.callback=true&timeout=10000&timestamp=1415800789364&unsubscribe.1.callback=false

訂閱的目的在於在註冊中心的數據發送變化的時候反向推送給訂閱方

directory.subscribe(url)最終調用註冊中心的RegsryService遠程服務, 它是一個普通的dubbo遠程調用。要說跟絕大多數dubbo遠程調用的區別:url的參數subscribe.1.callback=true它的意思是RegistryService的subscribe方法的第二個參數NotifyListener暴露爲回調服務; url的參數unsubscribe.1.callback=false的意思是RegistryService的unsubscribe方法的第二個參數NotifyListener暴露的回調服務銷燬。

 

這裏dubbo協議的註冊中心調註冊中心的服務採用的默認集羣調用策略是FailOver,選擇一臺註冊中心,只有當失敗的時候才重試其他服務器,註冊中心實現也比較簡單不具備集羣功能, 如果想要初步的集羣功能可以選用BroadcastCluster它至少向每個註冊中心遍歷調用註冊一遍

 

 

消費者引用服務

 <dubbo:registry protocol=”dubbo” address="127.0.0.1:9098" />

<dubbo:reference id="demoService"interface="com.alibaba.d ubbo.demo.DemoService"/>

1. 指定了哪種的註冊中心,是基於dubbo協議的,指定了註冊中心的地址以及端口號

2. 引用遠程DemoService服務

 

每個<dubbo:reference/>標籤spring加載的時候都會生成一個Referenc eBean。


如上圖ReferenceBean實現了spring的FactoryBean接口, 實現了此接口的Bean通過spring的BeanFactory.getBean(“beanName”)獲取的對象不是配置的bean本身而是通過FactoryBean.getObject()方法返回的對象,此接口在spring內部被廣泛使用,用來獲取代理對象等等。這裏getObjec t方法用來生成對遠程服務調用的代理

1. loadRegistries()獲取配置的註冊中心的registryUrls

2. 遍歷registryUrls集合,給registryUrl加上refer key就是要引用的遠程服務

[registry://127.0.0.1:9098/com.alibaba.dubbo.registry.RegistryService?application=demo-consumer&dubbo=2.0.0&pid=2484&refer=application%3Ddemo-consumer%26dubbo%3D2.0.0%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D2484%26side%3Dconsumer%26timestamp%3D1415879965901&registry=dubbo&timestamp=1415879990670]

3. 遍歷registryUrls集合,使用Protocol.refer(interface,regist ryUrl)的到可執行對象invoker

4. 如果註冊中心有多個的話, 通過集羣策略Cluser.join()將多個invoke r僞裝成一個可執行invoker, 這裏默認使用available策略

5. 利用代理工廠生成代理對象proxyFactory.getProxy(invoker)

 

 

Protocol.refer過程流程

1. 根據傳入的registryUrl是用來選擇RegistryProcol它的協議屬性是registry, 下面要選擇使用哪種註冊中心所以要根據REGISTRY_KEY屬性重新設置registrUrl

dubbo://127.0.0.1:9098/com.alibaba.dubbo.registry.RegistryService?application=demo-consumer&dubbo=2.0.0&pid=4524&refer=application%3Ddemo-consumer%26dubbo%3D2.0.0%26interface%3Dcom.alibaba.dubbo.demo.DemoService%26methods%3DsayHello%26pid%3D4524%26side%3Dconsumer%26timestamp%3D1415881461048&timestamp=1415881461113

2. 根據registrUrl利用RegistryFactory獲取註冊器(過程跟暴露服務那邊一樣), 這裏是dubbo協議得到的是註冊器是DubboRegistry

引用並訂閱註冊中心服務,

3. 構建引用服務的subscribeUrl

consumer://10.5.24.221/com.alibaba.dubbo.demo.DemoService?application=demo-consumer&category=consumers&check=false&dubbo=2.0.0&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=8536&side=consumer&timestamp=1415945205031

並通過註冊器向註冊中心註冊消費方, 主要這裏的category是consume rs

4. 構建目錄服務RegistryDirectory,

構建訂閱消費者訂閱url,這裏主要category=providers去註冊中心尋找註冊的服務提供者

consumer://10.33.37.4/com.alibaba.dubbo.demo.DemoService?application=demo-consumer&category=providers,configurators,routers&dubbo=2.0.0&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=9692&side=consumer&timestamp=1415967547508

向註冊中心訂閱消費方,註冊中心根據消費者傳入的url找到匹配的服務提供者url (注意:這裏服務提供者沒有設置category,註冊中心對於沒有設置的默認取providers) dubbo://10.33.37.4:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.5.4-SNAPSHOT&generic=false&interface=com.alibaba.dubbo.demo.DemoService&loadbalance=roundrobin&methods=sayHello&owner=william&pid=9828&side=provider&timestamp=1415968955329

然後註冊中心回調服務消費者暴露的回調接口來對服務提供者的服務進行引用refer生成對應的可執行對象invoker。服務提供者與服務的消費建立連接,

5. 通過Cluster合併directory中的invokers, 返回可執行對象invoker

6. ProxyFactory.getProxy(invoker) 創建代理對象返回給業務方使用

  

這裏dubbo協議的註冊中心調註冊中心的服務採用的默認集羣調用策略是FailOver,選擇一臺註冊中心,只有當失敗的時候才重試其他服務器,註冊中心實現也比較簡單不具備集羣功能, 如果想要初步的集羣功能可以選用BroadcastCluster它至少向每個註冊中心遍歷調用註冊一遍

發佈了69 篇原創文章 · 獲贊 99 · 訪問量 46萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章