1. 程式人生 > >dubbo中registry、route、directory、cluster、loadbalance、route的關係以及一個引用操作和呼叫操作到底幹了啥

dubbo中registry、route、directory、cluster、loadbalance、route的關係以及一個引用操作和呼叫操作到底幹了啥

zk是比較典型場景,所以註冊中心都是以zk作為例子的

 

1 對於registry,提供者沒有這個,消費者才有。為什麼?
因為只有消費者才需要去註冊中心拿到provide的資訊,而provider是不需要關注的,provider只需要去註冊就好。在RegistryProtocol的export方法中,可以看到在registry方法裡面直接在註冊中心寫資訊就夠了。

 

2 RegistryDirectory是啥意思?如果有三個zk,有幾個directory?幾個registry?
一個目錄其實就是很容易想到就是一個dubbo提供者的interfacename在zk上面的/duboo+interfacename的目錄,但不僅僅是這樣,如果有多個zk,那麼有三個目錄,因為這三個目錄在不同的zk上面。

一個消費者在初始化得到引用的時候,在loadRegistries裡面,如果url裡面有多個以分號隔開的註冊中心的ip+port,那麼就得到多個註冊中心的url,那麼每個url都需要經過registryProcol處理,具體來說createProxy裡面就是要對每個註冊url進行refer操作

所以directory的建構函式裡面有兩個東西來限定唯一性:註冊中心url和provider的interfacename。對於一個消費者,假設只有一個provider的interfacename需要引用的話,在三個zk的前提下,那麼要維護三個registry,三個registry都各自有自己的directory。消費者初始化引用的時候每個directory和對應的registry都需要一個方面跟提供者一樣,去不同的zk上面的consumer寫入自己的資訊,另外要分別訂閱這個interfaceface路徑下的provider、configure、route資訊。第一次訂閱的時候,順便把provider的具體資訊都存在directory的methodInvokerMap中,以後要呼叫的時候就從這裡取。

 

3 dubbo裡面經常說的FailoverClusterinvoer、BroadcastClusterInvoker等等這些Cluster是啥意思?

首先cluster介面只有一個方法,就是通過join得到一個invoker,不要被名字誤導了,雖然叫cluster,其實沒有儲存多個invoker,並不是儲存了一個集合。雖然叫join,但是其實是利用spi根據配置得到不同的cluster,可以理解成:cluster的join就是根據配置得到不同ClusterInvoker實現。當然還有一個MockClusterWrapper,所以所有的Cluster其實都被這個Wrapper都包了一層,這個是dubbo的spi注入做的,看名字就知道加這一層是為了提前攔截,方便mock測試用的。

 

4 Cluster和loadbalance的關係

不同的Cluster的實現裡面都有一個doInvoke方法,dubbo提供者被呼叫的時候都會走這個方法,因為cluster本質也是一個invoker,不同的Cluster具有不同的doInvoke實現,在遇到多個invoker呼叫不順利情況下 做不同處理。
而loadbalance不同,他是用來挑選優先使用哪個invoker的,一般有隨機、一致性雜湊,這個也是spi來挑選的。在cluster的共同的父類實現中,也就是在doinvoke之前,都會呼叫一次loadbalance的select來選出優先的invoker

 

5 dubbo與zk的關係咋樣的,dubbo怎麼被zk通知的?

我們說過provider是不需要監聽的,消費者才要。我感覺dubbo的zklistener太繞了,dubbox稍微好點。消費者在兩個地方進行監聽:與zk連線的statechanged回撥以及自己引用的interface目錄的provider、configure、route目錄發生變化的時候,也會有childchanged的回撥。
statechanged回撥的註冊應該比較好找,就是zkclient去連線zk的時候,建立的回撥註冊。這個裡的回撥處理是,一旦發現重連,那麼把已經註冊的、已經訂閱的全部劃分到failed的list裡面,zkregistry有一個心跳,定期檢查這些failed的list裡面是不是有資料,如果有那麼重新註冊、訂閱。
childchanged是在訂閱的時候註冊的,也就是doSubscribe裡面。當provider、configure、route發生變化的時候,最終呼叫到RegistryDirectory的notify方法,回撥的傳過來的引數是當前這個目錄比如provider目錄下面的實際子節點的全部資訊。以provider目錄為例子,拿到這些重要資訊以後,RegistryDirectory就會根據新的provider的url-list,做一次refreshInvoker,做之前還把快取的檔案也根據這個更新的。

所以說consumer就是通過這個回撥感知provider的變化的,看得出來如果zk回調出問題,dubbo就找不到提供者,並且快取檔案也壞了。並且dubbo沒有主動去輪訓檢查zk的當前資訊,這塊還是比較脆弱的。
我看dubbo官網說的是,阿里內部沒用zk,而是用自己的資料庫作為註冊中心。

 


6 refreshInvoker 裡面做了啥?
前面只是講到得到了一個provider的url、list,並沒有得到一個provider的實體,其實有了provider,需要使用dubboProcol的refer去真正引用一個service,與service建立長連結關係。底層建立transport層的通訊關係,我是使用netty4看的有時間可以寫寫。
至於序列化那塊,預設用的hessian,比較繁瑣。dubbo沒有用protobuf,如果用的話,效能更好,並且程式碼應該也不需要寫這麼多。所以沒有細研究了

 


7 消費者refer得到的到底是啥?
根據前面提到的,我們可以簡單總結下,假如有三個zk,那麼dorefer幹下面幾個事情:
建立三個registry、三個directory。
與三個registry建立長連結,建立consumer目錄上自己的資訊,這個叫註冊。
然後訂閱provider的資訊,並且把provider的url資訊拿到後refreshInvoker
與這些dubbo-invoker建立連線關係

 


8 那麼問題來了,refer方法結果是dubbo-invoker嗎?如果是的話 就用不到cluster、loadbalance這些了。
在doRefer方法的最後,還是呼叫了cluster.join(directory)得到invoke返回回去。也就是最終返回了三個MockClusterWrapper,裡面是FailoverClusterInvoker(預設spi)
對於directory或者說registry做了一次cluster.join,這是因為一個directory可能相同的版本的provider都不止一個,所以不同的provider是一個cluster,這裡面存在一個選擇。

剛剛外面說了返回了三個MockClusterWrapper,但是consumer或者說我們的業務使用者來說,不應該感知這些,所以對於三個註冊中心的三個MockClusterWrapper還要做一次cluster.join:
URL u = registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME);
invoker = cluster.join(new StaticDirectory(u, invokers));
這次是指定用了AvailableCluster,於是又返回了一個MockClusterInvoker,裡面包裹了真正的AvailableCluster,這個AvailableCluster的doInvoke方法就是遍歷自己的invoke-list,只要可用就用這個,也就是說三個zk,只要有一個沒問題,就直接用這個zk的url代表的provider
當然這個ref還要做一次proxy動態代理才能真正返回給使用者使用


9 Route是幹啥用的,在哪裡生效的?
在執行真正的invoke時候,為了使用cluster、loadbalance,必須經過clusterinvoke,在虛基類AbstractClusterInvoker的doInvoke方法中,首先是利用directory.list針對這個invocation做一次篩選,
List<Invoker<T>> invokers = doList(invocation);可以不用考慮,就是根據呼叫方法拿到invokers(這裡的invokers都是通過refreshinvokers拿到的),對於StaticDirectory直接返回所有invokers。
然後會用預設的MockInvokersSelector做一次route篩選處理,通過名字知道還是為了mock除錯用的。其他的route還有ConditionRouter和ScriptRouter,路由規則決定一次 dubbo 服務呼叫的目標伺服器。dubbo官網目前是試用階段。


10 一次呼叫進行了兩次cluster的選擇
一次呼叫,首先選擇任一一個可用registry或者說directory的invoker,也就是確定用這個註冊中心。後面還要選擇到底用這個註冊中心的哪個provider,預設spi是FailoverClusterinvoer,然後走loadbalance、cluster邏輯選出真正的invoker,走dubbo呼叫流程