日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Dubbo源码学习总结系列三 dubbo-cluster集群模块

發布時間:2025/4/9 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Dubbo源码学习总结系列三 dubbo-cluster集群模块 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ? ? Dubbo集群模塊的目的是將集群Invokers構造一個透明的Invoker對象,其中包含了容錯機制、負載均衡、目錄服務(服務地址集合)、路由機制等,為RPC層提供高可用、高并發、自動發現、可治理的SOA特性。

? ? ? ? 本文我們主要討論以下八個問題:

? ? ? ? 一、集群模塊的需求功能點有哪些?

? ? ? ? 二、集群模塊的總體設計框架是什么樣的?

? ? ? ? 三、Dubbo提供了哪些容錯機制?如何實現的?

? ? ? ? 四、Dubbo提供了哪些負載均衡機制?如何實現的?

? ? ? ? 五、Dubbo目錄服務是干什么的?提供了哪幾種類型的目錄服務?

? ? ? ? 六、Dubbo提供了哪些路由機制?如何實現的?

? ? ? ? 七、總結集群模塊如何帶來高可用、自動發現、可治理的特性?

?

? ? ? ? 一、集群模塊的需求功能點有哪些?

? ? ? ? 基于文章開頭討論的目標內容,我認為集群模塊的需求功能點主要有以下幾點:

? ? ? ? 1、將集群Invokers構造一個透明的Invoker對象提供給Rpc模塊調用;

? ? ? ? 2、提供容錯機制,包括Failover(失敗自動切換,嘗試其他服務器)、Failfast(失敗立即返回并拋出異常)、Failsafe(失敗忽略異常)、Failback(失敗自動恢復,記錄日志并定時重試)、Forking(并行調用多個服務,一個成功立即返回)、Broadcast(廣播調用所有提供者,任意一個報錯則報錯);

? ? ? ? 3、提供負載均衡機制,包括Random(帶權重的隨機訪問)、RoundRobin(帶權重的輪訓訪問)、LeastActive(選擇最少活躍者)、ConsistentHash(一致性哈希,相同參數的請求總是發到同一提供者);

? ? ? ? 4、提供目錄服務,包括靜態目錄服務(將調用地址存到本地)、注冊中心注冊目錄服務兩種方式;

? ? ? ? 5、提供路由機制,包括條件路由(在URL配置條件表達式)和腳本路由(使用腳本語言編寫腳本,返回路由結果);

?

? ? ? ? 二、集群模塊的總體設計框架是什么樣的?

? ? ? ? 調用關系如下圖所示:

? ? ? ??

?

? ? ? ? 接口聲明如下圖所示:

? ? ? ??

? ? ? ? Cluster接口:聲明join()方法,從Directory實例中的Invoker列表中返回一個Invoker;

? ? ? ? Directory接口:list()方法,可查詢Invoker列表;

? ? ? ? LoadBalance接口:select()方法,可從一個Invoker集合中結合負載均衡策略選擇一個Invoker返回;

? ? ? ? Router接口:route()方法,從給定的Invoker集合路由選擇一個Invoker返回;

? ? ? ? Merger接口:merge(T)方法,將多個調用返回的結果合并起來返回;

? ? ? ? Configurator接口:configure(URL)方法,配置加工URL參數并返回;

? ? ? ??

? ? ? ? ?三、Dubbo提供了哪些集群容錯機制?如何實現的?

? ? ? ? 由于篇幅過程,我將其內容單獨寫了一篇博客,詳見?《集群容錯機制》。

? ? ? ??

??????? 四、Dubbo提供了哪些負載均衡機制?如何實現的?

? ? ? ? 由于篇幅過長,我又將內容拆分到另一片博客,見《集群負載均衡》。

?

? ? ? ? 五、Dubbo目錄服務是干什么的?提供了哪幾種類型的目錄服務?

? ? ? ??dubbo目錄服務提供了獲取提供者服務地址列表的功能,目錄服務的調用者是com.alibaba.dubbo.rpc.cluster.Cluster的join()方法。目前dubbo提供了靜態目錄服務和注冊中心目錄服務。靜態目錄服務實現了一個靜態的地址列表本地內存緩存。注冊中心目錄服務提供了分布式注冊檢索服務地址的功能。在提供目錄服務返回服務地址的時候,調用dubbo的路由服務,實現了請求服務的路由功能。接下來,我們來討論目錄服務的實現細節。

? ? ? ? 1、Directory接口

? ? ? ??

? ? ? ? Directory接口中,

? ? ? ??Class<T> getInterface()方法返回服務的接口類;

? ? ? ? list(Invocation invocation)就是獲取服務地址列表的方法;

? ? ? ??父接口Node中,

? ? ? ??getUrl()方法返回了服務聲明的URL信息,

? ? ? ??isAvailable()方法判斷目錄服務是否可用,或者是否存在可用的服務提供者;

? ? ? ??destroy()銷毀目錄服務及所有提供者服務。

? ? ? ??

? ? ? ? 2、AbstractDirectory,目錄服務的默認實現抽象類;

? ? ? ? (1)將路由對象引入目錄服務,方法setRouters()設置了路由對象,實現見如下代碼:? ? ? ??

1 protected void setRouters(List<Router> routers) { 2 // copy list 3 routers = routers == null ? new ArrayList<Router>() : new ArrayList<Router>(routers); 4 // append url router 5 String routerkey = url.getParameter(Constants.ROUTER_KEY); 6 if (routerkey != null && routerkey.length() > 0) {
//通過SPI實例化配置的路由對象工廠對象
7 RouterFactory routerFactory = ExtensionLoader.getExtensionLoader(RouterFactory.class).getExtension(routerkey); 8 routers.add(routerFactory.getRouter(url)); 9 } 10 // append mock invoker selector 11 routers.add(new MockInvokersSelector()); 12 Collections.sort(routers); 13 this.routers = routers; 14 }

? ? ? ? ?(2)得到服務對象列表,主要通過doList()實現得到服務列表,此方法由子類實現,然后依次調用router列表做路由篩選,實現如下:

1 public List<Invoker<T>> list(Invocation invocation) throws RpcException { 2 if (destroyed) { 3 throw new RpcException("Directory already destroyed .url: " + getUrl()); 4 } 5 List<Invoker<T>> invokers = doList(invocation); 6 List<Router> localRouters = this.routers; // local reference 7 if (localRouters != null && localRouters.size() > 0) { 8 for (Router router : localRouters) { 9 try { 10 if (router.getUrl() == null || router.getUrl().getParameter(Constants.RUNTIME_KEY, false)) { 11 invokers = router.route(invokers, getConsumerUrl(), invocation); 12 } 13 } catch (Throwable t) { 14 logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t); 15 } 16 } 17 } 18 return invokers; 19 }

?

?

? ? ? ? 3、StaticDirectory靜態目錄服務,doList()將構造方法中傳入的invoker列表原樣返回。

? ? ? ? 4、RegistryDirectory 類整合了注冊中心和目錄服務,具體實現實在dubbo-register模塊,我將另外寫一篇博客討論。

?

? ? ? ? 六、Dubbo提供了哪些路由機制?如何實現的?

? ? ? ? 路由機制為用戶提供了靈活可配置的服務篩選功能,通過用戶自定義配置路由規則,決定一次 dubbo 服務調用的目標服務器。使用場景例如:提供差異化服務,給重要的請求提供性能好的服務器,反之給次要的服務提供性能差的服務器;讀寫分離,根據方法名字add,update,delete等分為一組,查詢方法分為一組,分別映射到不同的服務器上;對客戶端設置白名單、黑名單;更多場景及具體的應用說明詳見dubbo用戶手冊路由規則篇。

? ? ? ? dubbo提供了兩種路由機制:條件路由和腳本路由。

? ? ? ? 1、向注冊中心寫入路由規則,通常由監控中心或服務治理頁面完成,代碼實現主要在dubb-register模塊:

1 RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); 2 Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); 3 registry.register(URL.valueOf("condition://0.0.0.0/com.foo.BarService?category=routers&dynamic=false&rule=" + URL.encode("host = 10.20.153.10 => host = 10.20.153.11") + "));

? ? ? ? 其中:

  • condition://?表示路由規則的類型,支持條件路由規則和腳本路由規則,可擴展,必填。
  • 0.0.0.0?表示對所有 IP 地址生效,如果只想對某個 IP 的生效,請填入具體 IP,必填。
  • com.foo.BarService?表示只對指定服務生效,必填。
  • category=routers?表示該數據為動態配置類型,必填。
  • dynamic=false?表示該數據為持久數據,當注冊方退出時,數據依然保存在注冊中心,必填。
  • enabled=true?覆蓋規則是否生效,可不填,缺省生效。
  • force=false?當路由結果為空時,是否強制執行,如果不強制執行,路由結果為空的路由規則將自動失效,可不填,缺省為?flase。
  • runtime=false?是否在每次調用時執行路由規則,否則只在提供者地址列表變更時預先執行并緩存結果,調用時直接從緩存中獲取路由結果。如果用了參數路由,必須設為?true,需要注意設置會影響調用的性能,可不填,缺省為?flase。
  • priority=1?路由規則的優先級,用于排序,優先級越大越靠前執行,可不填,缺省為?0。
  • rule=URL.encode("host = 10.20.153.10 => host = 10.20.153.11")?表示路由規則的內容,必填。

?

? ? ? ? 2、條件路由

? ? ? ??基于條件表達式的路由規則,如:host = 10.20.153.10 => host = 10.20.153.11。=>左邊的表達式表示消費端信息(matchWhen),右邊的表達式表示服務提供者的服務信息(matchThen)。

? ? ? ? 代碼實現中,解析=>左右的條件表達式,左側消費端條件表達式解析成when,右側服務端條件表達式解析成then,封裝matchWhen()和matchThen()分別匹配消費端和服務端表達式。

? ? ? ? 我們看看源碼如何實現路由邏輯的。

? ? ? ? 條件路由實現主要靠兩個類,ConditionRouterFactory,實現了ConditionRouter實例化的過程;ConditionRouter,實現了具體的路由機制,其中route方法實現如下,實現主要靠解析和匹配條件表達式。

1 public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) 2 throws RpcException { 3 if (invokers == null || invokers.size() == 0) { 4 return invokers; 5 } 6 try {
//消費端條件不匹配規則,就全部返回
7 if (!matchWhen(url, invocation)) { 8 return invokers; 9 } 10 List<Invoker<T>> result = new ArrayList<Invoker<T>>(); 11 if (thenCondition == null) { 12 logger.warn("The current consumer in the service blacklist. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey()); 13 return result; 14 } 15 for (Invoker<T> invoker : invokers) {
//遍歷invokers,找到匹配規則的invoker(服務端)加入result
16 if (matchThen(invoker.getUrl(), url)) { 17 result.add(invoker); 18 } 19 } 20 if (result.size() > 0) { 21 return result; 22 } else if (force) { //如果結果為空,force=true,則返回空的列表,否則返回所有的invokers(不執行route規則) 23 logger.warn("The route result is empty and force execute. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey() + ", router: " + url.getParameterAndDecoded(Constants.RULE_KEY)); 24 return result; 25 } 26 } catch (Throwable t) { 27 logger.error("Failed to execute condition router rule: " + getUrl() + ", invokers: " + invokers + ", cause: " + t.getMessage(), t); 28 } 29 return invokers; 30 }

??

?? ? ? ? 3、腳本路由

? ? ? ? 通過配置腳本或腳本文件設置路由規則rule,程序編譯執行腳本函數,得到腳本篩選后的invokers數組。具體邏輯很簡單,就是加載腳本,加載對應腳本引擎,執行腳本,得到結果后轉換輸出的過程。

1 public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException { 2 try { 3 List<Invoker<T>> invokersCopy = new ArrayList<Invoker<T>>(invokers); 4 Compilable compilable = (Compilable) engine; 5 Bindings bindings = engine.createBindings(); 6 bindings.put("invokers", invokersCopy); 7 bindings.put("invocation", invocation); 8 bindings.put("context", RpcContext.getContext()); 9 CompiledScript function = compilable.compile(rule); 10 Object obj = function.eval(bindings); 11 if (obj instanceof Invoker[]) { 12 invokersCopy = Arrays.asList((Invoker<T>[]) obj); 13 } else if (obj instanceof Object[]) { 14 invokersCopy = new ArrayList<Invoker<T>>(); 15 for (Object inv : (Object[]) obj) { 16 invokersCopy.add((Invoker<T>) inv); 17 } 18 } else { 19 invokersCopy = (List<Invoker<T>>) obj; 20 } 21 return invokersCopy; 22 } catch (ScriptException e) { 23 //fail then ignore rule .invokers. 24 logger.error("route error , rule has been ignored. rule: " + rule + ", method:" + invocation.getMethodName() + ", url: " + RpcContext.getContext().getUrl(), e); 25 return invokers; 26 } 27 }

?

?? ? ? ? 七、總結集群模塊如何帶來高可用、自動發現、可治理的特性?

? ? ? ? ?集群模塊在dubbo中非常重要,提供了基于RPC功能的高可用特性,此特性主要是通過集群容錯和負載均衡策略支持的,在服務提供者出現異常時,可配置的容錯特性確保服務能按照配置的策略返回,或切換到其他服務并重試,或立即拋出異常,滿足了不同服務不同場景的異常后處理需要。可配置的負載均衡策略滿足了不同場景、需求的服務實現負載均衡,在不同場景下均勻的分攤負載,在負載不夠用的情況下靈活的增加機器節點承擔多余的負載,保證了集群的高可用特性。并且可以靈活配置節點的權重,實現針對不同配置的服務節點承擔的請求不同。

? ? ? ? 可配置的路由功能滿足了很多場景下的靈活路由需求,如讀寫分離,消費端請求的白名單、黑名單,針對不同配置的服務提供給不同的消費者等等。由于可配置性強,可以針對不同的需求做不同的配置,可提供很靈活的功能特性。通過配置規則,實現服務降級,可以屏蔽有問題的服務,并定義服務響應。這些都體現了Dubbo可治理的特性。

? ? ? ? 目錄服務簡單的定義了對服務地址列表的查詢功能,配合dubb-register注冊中心模塊功能可以實現服務注冊、自動發現功能。詳見注冊中心模塊的源碼分析章節。

? ? ? ? 集群模塊就討論到這里了,如有不當之處,歡迎大家提出異議和寶貴的意見,這樣有助于我技術上的提升。

轉載于:https://www.cnblogs.com/markcd/p/8454569.html

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的Dubbo源码学习总结系列三 dubbo-cluster集群模块的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。