1. 程式人生 > 程式設計 >Dubbo原始碼解析(三十四)叢集——開篇

Dubbo原始碼解析(三十四)叢集——開篇

叢集——開篇

目標:介紹接下來叢集分哪幾部分來描述,介紹dubbo在叢集中涉及到的幾個功能,介紹dubbo-cluster下跟各個功能相關的介面

叢集是什麼?

如果說分散式是爸爸住在杭州,媽媽住在上海,那麼叢集就是兩個爸爸,一個住在杭州,一個住在上海。對於分散式和叢集有高吞吐量、高可用的目標。對於分散式來說每個伺服器部署的服務任務是不同的,可能需要這些伺服器上的服務共同協作才能完成整個業務流程,各個服務各司其職。而叢集不一樣,叢集是同一個服務,被部署在了多個伺服器上,每個伺服器的任務都是一樣的,是為了減少壓力集中的問題,而叢集中就會出現負載均衡、容錯等問題。

dubbo的叢集涉及到以下幾部分內容:

  1. 目錄:Directory可以看成是多個Invoker的集合,但是它的值會隨著註冊中心中服務變化推送而動態變化,那麼Invoker以及如何動態變化就是一個重點內容。
  2. 叢集容錯:Cluster 將 Directory 中的多個 Invoker 偽裝成一個 Invoker,對上層透明,偽裝過程包含了容錯邏輯,呼叫失敗後,重試另一個。
  3. 路由:dubbo路由規則,路由規則決定了一次dubbo服務呼叫的目標伺服器,路由規則分兩種:條件路由規則和指令碼路由規則,並且支援可拓展。
  4. 負載均衡策略:dubbo支援的所有負載均衡策略演演算法。
  5. 配置:根據url上的配置規則生成配置資訊
  6. 分組聚合:合併返回結果。
  7. 本地偽裝:mork通常用於服務降級,mock只在出現非業務異常(比如超時,網路異常等)時執行

以上幾部分跟《dubbo原始碼解析(一)Hello,Dubbo》的"(二)dubbo-cluster——叢集模組“介紹有些類似,這裡再重新講一遍是為了明確我接下來介紹叢集模組的文章內容分佈,也就是除了本文之外,我會用七篇文章來講解以上的七部分,不管內容多少,只是為了把相應內容區分開來,能讓讀者有選擇性的閱讀。

在官方網站上有一段介紹我覺得寫的非常的好:

叢集工作過程可分為兩個階段,第一個階段是在服務消費者初始化期間,叢集 Cluster 實現類為服務消費者建立 Cluster Invoker 例項,即上圖中的 merge 操作。第二個階段是在服務消費者進行遠端呼叫時。以 FailoverClusterInvoker 為例,該型別 Cluster Invoker 首先會呼叫 Directory 的 list 方法列舉 Invoker 列表(可將 Invoker 簡單理解為服務提供者)。Directory 的用途是儲存 Invoker,可簡單類比為 List<invoker>。其實現類 RegistryDirectory 是一個動態服務目錄,可感知註冊中心配置的變化,它所持有的 Inovker 列表會隨著註冊中心內容的變化而變化。每次變化後,RegistryDirectory 會動態增刪 Inovker,並呼叫 Router 的 route 方法進行路由,過濾掉不符合路由規則的 Invoker。當 FailoverClusterInvoker 拿到 Directory 返回的 Invoker 列表後,它會通過 LoadBalance 從 Invoker 列表中選擇一個 Inovker。最後 FailoverClusterInvoker 會將引數傳給 LoadBalance 選擇出的 Invoker 例項的 invoker 方法,進行真正的遠端呼叫。

本文要來講的無非就是這幾部分內容的一個大概,並且介紹一下這幾部分內容涉及到的介面。叢集的包結構我就不在這裡展示了,就是《dubbo原始碼解析(一)Hello,Dubbo》的"(二)dubbo-cluster——叢集模組“中的圖片。下面我們直接對應各個部分來介紹相應的介面原始碼。

目錄

cluster

關於目錄介紹請檢視《dubbo原始碼解析(一)Hello,Dubbo》的"(二)dubbo-cluster——叢集模組“介紹。

原始碼分析

(一)Cluster

@SPI(FailoverCluster.NAME)
public interface Cluster {

    /**
     * Merge the directory invokers to a virtual invoker.
     * 將目錄呼叫程式合併到虛擬呼叫程式。
     * @param <T>
     * @param directory
     * @return cluster invoker
     * @throws RpcException
     */
    @Adaptive
    <T> Invoker<T> join(Directory<T> directory) throws RpcException;

}
複製程式碼

該介面是叢集容錯介面,可以看到它是一個可擴充套件介面,預設實現FailoverCluster,當然它還會有其他的實現,每一種實現都代表了一種叢集容錯的方式,具體有哪些,可以看下面文章的介紹,他們都在support包下面,在本文只是讓讀者知道介面的定義。那麼它還定義了一個join方法,作用就是把Directory物件變成一個 Invoker 物件用來後續的一系列呼叫。該Invoker代表了一個叢集實現。似懂非懂就夠了,後面看具體的實現會比較清晰。

(二)Configurator

public interface Configurator extends Comparable<Configurator> {

    /**
     * get the configurator url.
     * 配置規則,生成url
     * @return configurator url.
     */
    URL getUrl();

    /**
     * Configure the provider url.
     * 把規則配置到URL中
     *
     * @param url - old rovider url.
     * @return new provider url.
     */
    URL configure(URL url);

}
複製程式碼

該介面是配置規則的介面,定義了兩個方法,第一個是配置規則,並且生成url,第二個是把配置配置到舊的url中,其實都是在url上應用規則。

(三)ConfiguratorFactory

@SPI
public interface ConfiguratorFactory {

    /**
     * get the configurator instance.
     * 獲得configurator例項
     * @param url - configurator url.
     * @return configurator instance.
     */
    @Adaptive("protocol")
    Configurator getConfigurator(URL url);

}
複製程式碼

該介面是Configurator的工廠介面,定義了一個getConfigurator方法來獲得Configurator例項,比較好理解。

(四)Directory

public interface Directory<T> extends Node {

    /**
     * get service type.
     * 獲得服務型別
     * @return service type.
     */
    Class<T> getInterface();

    /**
     * list invokers.
     * 獲得所有服務Invoker集合
     * @return invokers
     */
    List<Invoker<T>> list(Invocation invocation) throws RpcException;

}
複製程式碼

該介面是目錄介面,Directory 代表了多個 Invoker,並且它的值會隨著註冊中心的服務變更推送而變化 。一個服務型別對應一個Directory。定義的兩個方法也比較好理解。

(五)LoadBalance

@SPI(RandomLoadBalance.NAME)
public interface LoadBalance {

    /**
     * select one invoker in list.
     * 選擇一個合適的呼叫,並且返回
     * @param invokers   invokers.
     * @param url        refer url
     * @param invocation invocation.
     * @return selected invoker.
     */
    @Adaptive("loadbalance")
    <T> Invoker<T> select(List<Invoker<T>> invokers,URL url,Invocation invocation) throws RpcException;

}
複製程式碼

該介面是負載均衡的介面,dubbo也提供了四種負載均衡策略,也會在下面文章講解。

(六)Merger

@SPI
public interface Merger<T> {

    /**
     * 合併T陣列,返回合併後的T物件
     * @param items
     * @return
     */
    T merge(T... items);

}
複製程式碼

該介面是分組聚合,將某物件陣列合併為一個物件。

(七)Router

public interface Router extends Comparable<Router> {

    /**
     * get the router url.
     * 獲得路由規則的url
     * @return url
     */
    URL getUrl();

    /**
     * route.
     * 篩選出跟規則匹配的Invoker集合
     * @param invokers
     * @param url        refer url
     * @param invocation
     * @return routed invokers
     * @throws RpcException
     */
    <T> List<Invoker<T>> route(List<Invoker<T>> invokers,Invocation invocation) throws RpcException;

}
複製程式碼

該介面是路由規則的介面,定義的兩個方法,第一個方法是獲得路由規則的url,第二個方法是篩選出跟規則匹配的Invoker集合。

(八)RouterFactory

@SPI
public interface RouterFactory {

    /**
     * Create router.
     * 建立路由
     * @param url
     * @return router
     */
    @Adaptive("protocol")
    Router getRouter(URL url);

}
複製程式碼

該介面是路由工廠介面,定義了獲得路由例項的方法。

後記

該部分相關的原始碼解析地址:github.com/CrazyHZM/in…

該文章大致講解了dubbo中叢集模組的內容,並且講解了相關介面的設計。接下來我將開始對cluster叢集模組中的叢集容錯部分,也就是support中的原始碼進行講解。