關(guān)于Dubbo的問(wèn)題有哪些

這篇文章主要講解了“關(guān)于Dubbo的問(wèn)題有哪些”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“關(guān)于Dubbo的問(wèn)題有哪些”吧!

創(chuàng)新互聯(lián)-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比敖漢網(wǎng)站開(kāi)發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫(kù),直接使用。一站式敖漢網(wǎng)站制作公司更省心,省錢(qián),快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋敖漢地區(qū)。費(fèi)用合理售后完善,十余年實(shí)體公司更值得信賴。

1、RPC

1.1 RPC 定義

互聯(lián)網(wǎng)公司的系統(tǒng)有成千上萬(wàn)個(gè)大大小小的服務(wù)組成,服務(wù)各自部署在不同的機(jī)器上,服務(wù)間的調(diào)用需要用到網(wǎng)絡(luò)通信,服務(wù)消費(fèi)方每調(diào)用一個(gè)服務(wù)都要寫(xiě)一坨網(wǎng)絡(luò)通信相關(guān)的代碼,不僅復(fù)雜而且極易出錯(cuò)。還要考慮新服務(wù)依賴?yán)戏?wù)時(shí)如何調(diào)用老服務(wù),別的服務(wù)依賴新服務(wù)的時(shí)候新服務(wù)如何發(fā)布方便他人調(diào)用。如何解決這個(gè)問(wèn)題呢?業(yè)界一般采用RPC遠(yuǎn)程調(diào)用的方式來(lái)實(shí)現(xiàn)。

關(guān)于Dubbo的問(wèn)題有哪些

RPC:

Remote Procedure Call Protocol 既  遠(yuǎn)程過(guò)程調(diào)用,一種能讓我們像調(diào)用本地服務(wù)一樣調(diào)用遠(yuǎn)程服務(wù),可以讓調(diào)用者對(duì)網(wǎng)絡(luò)通信這些細(xì)節(jié)無(wú)感知,比如服務(wù)消費(fèi)方在執(zhí)行  helloWorldService.sayHello("sowhat")  時(shí),實(shí)質(zhì)上調(diào)用的是遠(yuǎn)端的服務(wù)。這種方式其實(shí)就是RPC,RPC思想在各大互聯(lián)網(wǎng)公司中被廣泛使用,如阿里巴巴的dubbo、當(dāng)當(dāng)?shù)腄ubbox 、Facebook 的  thrift、Google 的grpc、Twitter的finagle等。

1.2 RPC demo

說(shuō)了那么多,還是實(shí)現(xiàn)一個(gè)簡(jiǎn)易版的RPC demo吧。

1.2.1 公共接口

public interface SoWhatService {     String sayHello(String name);   }

1.2.2 服務(wù)提供者

接口類實(shí)現(xiàn)

public class SoWhatServiceImpl implements SoWhatService {  @Override  public String sayHello(String name)  {   return "你好啊 " + name;  } }

服務(wù)注冊(cè)對(duì)外提供者

/**  * 服務(wù)注冊(cè)對(duì)外提供者  */  public class ServiceFramework {  public static void export(Object service, int port) throws Exception  {   ServerSocket server = new ServerSocket(port);   while (true)   {    Socket socket = server.accept();    new Thread(() ->    {     try     {      //反序列化      ObjectInputStream input = new ObjectInputStream(socket.getInputStream());      //讀取方法名      String methodName =(String) input.readObject();      //參數(shù)類型      Class<?>[] parameterTypes = (Class<?>[]) input.readObject();      //參數(shù)      Object[] arguments = (Object[]) input.readObject();      //找到方法      Method method = service.getClass().getMethod(methodName, parameterTypes);      //調(diào)用方法      Object result = method.invoke(service, arguments);      // 返回結(jié)果      ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());      output.writeObject(result);     } catch (Exception e)     {      e.printStackTrace();     }    }).start();   }  } }

服務(wù)運(yùn)行

public class ServerMain {  public static void main(String[] args)  {   //服務(wù)提供者 暴露出接口   SoWhatService service = new SoWhatServiceImpl();   try   {    ServiceFramework.export(service, 1412);   } catch (Exception e)   {    e.printStackTrace();   }  } }

1.2.3 服務(wù)調(diào)用者

動(dòng)態(tài)代理調(diào)用遠(yuǎn)程服務(wù)

/**  * @author sowhat  * 動(dòng)態(tài)代理調(diào)用遠(yuǎn)程服務(wù)  */ public class RpcFunction {  public static <T> T refer(Class<T> interfaceClass, String host, int port) throws Exception  {   return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[]{interfaceClass},     new InvocationHandler()     {      @Override      public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable      {       //指定 provider 的 ip 和端口       Socket socket = new Socket(host, port);       ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());       //傳方法名       output.writeObject(method.getName());       //傳參數(shù)類型       output.writeObject(method.getParameterTypes());       //傳參數(shù)值       output.writeObject(arguments);       ObjectInputStream input = new ObjectInputStream(socket.getInputStream());       //讀取結(jié)果       Object result = input.readObject();       return result;      }     });  } }

調(diào)用方法

public class RunMain {  public static void main(String[] args)  {   try   {    //服務(wù)調(diào)用者 需要設(shè)置依賴    SoWhatService service = RpcFunction.refer(SoWhatService.class, "127.0.0.1", 1412);    System.out.println(service.sayHello(" sowhat1412"));   } catch (Exception e)   {    e.printStackTrace();   }  } }

2、Dubbo 框架設(shè)計(jì)

2.1 Dubbo 簡(jiǎn)介

Dubbo 是阿里巴巴研發(fā)開(kāi)源工具,主要分為2.6.x 跟 2.7.x 版本。是一款分布式、高性能、透明化的 RPC  服務(wù)框架,提供服務(wù)自動(dòng)注冊(cè)、自動(dòng)發(fā)現(xiàn)等高效服務(wù)治理方案,可以和Spring 框架無(wú)縫集成,它提供了6大核心能力:

1. 面向接口代理的高性能RPC調(diào)用

2. 智能容錯(cuò)和負(fù)載均衡

3. 服務(wù)自動(dòng)注冊(cè)和發(fā)現(xiàn)

4. 高度可擴(kuò)展能力

5. 運(yùn)行期流量調(diào)度

6. 可視化的服務(wù)治理與運(yùn)維

關(guān)于Dubbo的問(wèn)題有哪些

調(diào)用過(guò)程:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 服務(wù)提供者 Provider 啟動(dòng)然后向 Registry 注冊(cè)自己所能提供的服務(wù)。

  3. 服務(wù)消費(fèi)者 Consumer 向Registry訂閱所需服務(wù),Consumer 解析Registry提供的元信息,從服務(wù)中通過(guò)負(fù)載均衡選擇  Provider調(diào)用。

  4. 服務(wù)提供方 Provider 元數(shù)據(jù)變更的話Registry會(huì)把變更推送給Consumer,以此保證Consumer獲得最新可用信息。

注意點(diǎn):

Provider 跟 Consumer 在內(nèi)存中記錄調(diào)用次數(shù)跟時(shí)間,定時(shí)發(fā)送統(tǒng)計(jì)數(shù)據(jù)到Monitor,發(fā)送的時(shí)候是短連接。

Monitor 跟 Registry 是可選的,可直接在配置文件中寫(xiě)好,Provider 跟 Consumer進(jìn)行直連。

Monitor 跟 Registry 掛了也沒(méi)事, Consumer 本地緩存了 Provider 信息。

Consumer 直接調(diào)用 Provider 不會(huì)經(jīng)過(guò) Registry。Provider、Consumer這倆到 Registry之間是長(zhǎng)連接。

2.2 Dubbo框架分層

關(guān)于Dubbo的問(wèn)題有哪些

如上圖,總的而言 Dubbo 分為三層。

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. Busines層:由用戶自己來(lái)提供接口和實(shí)現(xiàn)還有一些配置信息。

  3. RPC層:真正的RPC調(diào)用的核心層,封裝整個(gè)RPC的調(diào)用過(guò)程、負(fù)載均衡、集群容錯(cuò)、代理。

  4. Remoting層:對(duì)網(wǎng)絡(luò)傳輸協(xié)議和數(shù)據(jù)轉(zhuǎn)換的封裝。

如果每一層再細(xì)分下去,一共有十層。

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 接口服務(wù)層(Service):該層與業(yè)務(wù)邏輯相關(guān),根據(jù) provider 和 consumer 的業(yè)務(wù)設(shè)計(jì)對(duì)應(yīng)的接口和實(shí)現(xiàn)。

  3. 配置層(Config):對(duì)外配置接口,以 ServiceConfig 和 ReferenceConfig 為中心初始化配置。

  4. 服務(wù)代理層(Proxy):服務(wù)接口透明代理,Provider跟Consumer都生成代理類,使得服務(wù)接口透明,代理層實(shí)現(xiàn)服務(wù)調(diào)用跟結(jié)果返回。

  5. 服務(wù)注冊(cè)層(Registry):封裝服務(wù)地址的注冊(cè)和發(fā)現(xiàn),以服務(wù) URL 為中心。

  6. 路由層(Cluster):封裝多個(gè)提供者的路由和負(fù)載均衡,并橋接注冊(cè)中心,以Invoker 為中心,擴(kuò)展接口為  Cluster、Directory、Router 和 LoadBlancce。

  7. 監(jiān)控層(Monitor):RPC 調(diào)用次數(shù)和調(diào)用時(shí)間監(jiān)控,以 Statistics 為中心,擴(kuò)展接口為 MonitorFactory、Monitor 和  MonitorService。

  8. 遠(yuǎn)程調(diào)用層(Protocal):封裝 RPC 調(diào)用,以 Invocation 和 Result 為中心,擴(kuò)展接口為 Protocal、Invoker 和  Exporter。

  9. 信息交換層(Exchange):封裝請(qǐng)求響應(yīng)模式,同步轉(zhuǎn)異步。以 Request 和Response 為中心,擴(kuò)展接口為  Exchanger、ExchangeChannel、ExchangeClient 和 ExchangeServer。

  10. 網(wǎng)絡(luò)傳輸層(Transport):抽象 mina 和 netty 為統(tǒng)一接口,以 Message 為中心,擴(kuò)展接口為  Channel、Transporter、Client、Server 和 Codec。

  11. 數(shù)據(jù)序列化層(Serialize):可復(fù)用的一些工具,擴(kuò)展接口為 Serialization、ObjectInput、ObjectOutput 和  ThreadPool。

他們之間的調(diào)用關(guān)系直接看下面官網(wǎng)圖即可。

關(guān)于Dubbo的問(wèn)題有哪些

3、Dubbo SPI 機(jī)制

Dubbo 采用 微內(nèi)核設(shè)計(jì) + SPI 擴(kuò)展技術(shù)來(lái)搭好核心框架,同時(shí)滿足用戶定制化需求。這里重點(diǎn)說(shuō)下SPI。

3.1 微內(nèi)核

操作系統(tǒng)層面的微內(nèi)核跟宏內(nèi)核:

微內(nèi)核Microkernel:是一種內(nèi)核的設(shè)計(jì)架構(gòu),由盡可能精簡(jiǎn)的程序所組成,以實(shí)現(xiàn)一個(gè)操作系統(tǒng)所需要的最基本功能,包括了底層的尋址空間管理、線程管理、與進(jìn)程間通信。成功案例是QNX系統(tǒng),比如黑莓手機(jī)跟車用市場(chǎng)。

宏內(nèi)核Monolithic :把 進(jìn)程管理、內(nèi)存管理、文件系統(tǒng)、進(jìn)程通信等功能全部作為內(nèi)核來(lái)實(shí)現(xiàn),而微內(nèi)核則僅保留最基礎(chǔ)的功能,Linux  就是宏內(nèi)核架構(gòu)設(shè)計(jì)。

Dubbo中的廣義微內(nèi)核:

思想是 核心系統(tǒng) +  插件,說(shuō)白了就是把不變的功能抽象出來(lái)稱為核心,把變動(dòng)的功能作為插件來(lái)擴(kuò)展,符合開(kāi)閉原則,更容易擴(kuò)展、維護(hù)。比如小霸王游戲機(jī)中機(jī)體本身作為核心系統(tǒng),游戲片就是插件。vscode、Idea、chrome等都是微內(nèi)核的產(chǎn)物。

微內(nèi)核架構(gòu)其實(shí)是一直架構(gòu)思想,可以是框架層面也可以是某個(gè)模塊設(shè)計(jì),它的本質(zhì)就是將變化的部分抽象成插件,使得可以快速簡(jiǎn)便地滿足各種需求又不影響整體的穩(wěn)定性。

3.2 SPI 含義

主流的數(shù)據(jù)庫(kù)有MySQL、Oracle、DB2等,這些數(shù)據(jù)庫(kù)是不同公司開(kāi)發(fā)的,它們的底層協(xié)議不大一樣,那怎么約束呢?一般就是定制統(tǒng)一接口,具體實(shí)現(xiàn)不管,反正面向相同的接口編程即可。等到真正使用的時(shí)候用具體的實(shí)現(xiàn)類就好,問(wèn)題是哪里找用那個(gè)實(shí)現(xiàn)類呢?這時(shí)候就采用約定好的法則將實(shí)現(xiàn)類寫(xiě)到指定位置即可。

SPI 全稱為 Service Provider  Interface,是一種服務(wù)發(fā)現(xiàn)機(jī)制。它約定在ClassPath路徑下的META-INF/services文件夾查找文件,自動(dòng)加載文件里所定義的類。

3.3 SPI demo

接口:

package com.example.demo.spi;  public interface SPIService {     void execute(); }

實(shí)現(xiàn)類1:

public class SpiImpl1 implements SPIService{  @Override     public void execute() {         System.out.println("SpiImpl1.execute()");     } }

實(shí)現(xiàn)類2:

public class SpiImpl2 implements SPIService{  @Override     public void execute() {   System.out.println("SpiImpl2.execute()");     } }

配置路徑

關(guān)于Dubbo的問(wèn)題有哪些

調(diào)用加載類

package com.example.demo.spi; import sun.misc.Service; import java.util.Iterator; import java.util.ServiceLoader;  public class Test {     public static void main(String[] args) {             Iterator<SPIService> providers = Service.providers(SPIService.class);         ServiceLoader<SPIService> load = ServiceLoader.load(SPIService.class);          while(providers.hasNext()) {             SPIService ser = providers.next();             ser.execute();         }         System.out.println("--------------------------------");         Iterator<SPIService> iterator = load.iterator();         while(iterator.hasNext()) {             SPIService ser = iterator.next();             ser.execute();         }     } }

3.4 SPI源碼追蹤

ServiceLoader.load(SPIService.class) 底層調(diào)用大致邏輯如下:圖片iterator.hasNext() 跟  iterator.next()底層調(diào)用大致如下:

關(guān)于Dubbo的問(wèn)題有哪些

3.5 Java SPI缺點(diǎn)

不能按需加載,Java SPI在加載擴(kuò)展點(diǎn)的時(shí)候,會(huì)一次性加載所有可用的擴(kuò)展點(diǎn),很多是不需要的,會(huì)浪費(fèi)系統(tǒng)資源。

獲取某個(gè)實(shí)現(xiàn)類的方式不夠靈活,只能通過(guò) Iterator 形式獲取,不能根據(jù)某個(gè)參數(shù)來(lái)獲取對(duì)應(yīng)的實(shí)現(xiàn)類。

不支持AOP與依賴注入,JAVA SPI可能會(huì)丟失加載擴(kuò)展點(diǎn)異常信息,導(dǎo)致追蹤問(wèn)題很困難。

3.6 Dubbo SPI

JDK自帶的不好用Dubbo 就自己實(shí)現(xiàn)了一個(gè) SPI,該SPI 可以通過(guò)名字實(shí)例化指定的實(shí)現(xiàn)類,并且實(shí)現(xiàn)了 IOC 、AOP 與 自適應(yīng)擴(kuò)展 SPI  。

key = com.sowhat.value

Dubbo 對(duì)配置文件目錄的約定,不同于 Java SPI ,Dubbo 分為了三類目錄。

META-INF/services/ :該目錄下 SPI 配置文件是為了用來(lái)兼容 Java SPI 。

META-INF/dubbo/ :該目錄存放用戶自定義的 SPI 配置文件。

META-INF/dubbo/internal/ :該目錄存 Dubbo 內(nèi)部使用的 SPI 配置文件。

使用的話很簡(jiǎn)單 引入依賴,然后百度教程即可。

@Test  void sowhat()  {   ExtensionLoader<SPIService> spiService = ExtensionLoader.getExtensionLoader(SPIService.class);        //按需獲取實(shí)現(xiàn)類對(duì)象   SPIService demo1 = spiService.getExtension("SpiImpl1");   demo1.execute();  }

3.7 Dubbo SPI源碼追蹤

ExtensionLoader.getExtension 方法的整個(gè)思路是  查找緩存是否存在,不存在則讀取SPI文件,通過(guò)反射創(chuàng)建類,然后設(shè)置依賴注入這些東西,有包裝類就包裝下,執(zhí)行流程如下圖所示:

關(guān)于Dubbo的問(wèn)題有哪些

說(shuō)下重要的四個(gè)部分:

1.injectExtension IOC

查找 set 方法,根據(jù)參數(shù)找到依賴對(duì)象則注入。

2.WrapperClass AOP

包裝類,Dubbo 幫你自動(dòng)包裝,只需要某個(gè)擴(kuò)展類的構(gòu)造函數(shù)只有一個(gè)參數(shù),并且是擴(kuò)展接口類型,就會(huì)被判定為包裝類。

3.Activate

Active 有三個(gè)屬性,group 表示修飾在哪個(gè)端,是 provider 還是 consumer,value 表示在  URL參數(shù)中出現(xiàn)才會(huì)被激活,order 表示實(shí)現(xiàn)類的順序。

3.8 Adaptive 自適應(yīng)擴(kuò)展

需求:根據(jù)配置來(lái)進(jìn)行 SPI  擴(kuò)展的加載后不想在啟動(dòng)的時(shí)候讓擴(kuò)展被加載,想根據(jù)請(qǐng)求時(shí)候的參數(shù)來(lái)動(dòng)態(tài)選擇對(duì)應(yīng)的擴(kuò)展。實(shí)現(xiàn):Dubbo用代理機(jī)制實(shí)現(xiàn)了自適應(yīng)擴(kuò)展,為用戶想擴(kuò)展的接口 通過(guò)JDK  或者 Javassist 編譯生成一個(gè)代理類,然后通過(guò)反射創(chuàng)建實(shí)例。實(shí)例會(huì)根據(jù)本來(lái)方法的請(qǐng)求參數(shù)得知需要的擴(kuò)展類,然后通過(guò)  ExtensionLoader.getExtensionLoader(type.class).getExtension(name)來(lái)獲取真正的實(shí)例來(lái)調(diào)用,看個(gè)官網(wǎng)樣例。

public interface WheelMaker {     Wheel makeWheel(URL url); } // WheelMaker 接口的自適應(yīng)實(shí)現(xiàn)類 public class AdaptiveWheelMaker implements WheelMaker {     public Wheel makeWheel(URL url) {         if (url == null) {             throw new IllegalArgumentException("url == null");         }      // 1. 調(diào)用 url 的 getXXX 方法獲取參數(shù)值         String wheelMakerName = url.getParameter("Wheel.maker");         if (wheelMakerName == null) {             throw new IllegalArgumentException("wheelMakerName == null");         }         // 2. 調(diào)用 ExtensionLoader 的 getExtensionLoader 獲取加載器         // 3. 調(diào)用 ExtensionLoader 的 getExtension 根據(jù)從url獲取的參數(shù)作為類名稱加載實(shí)現(xiàn)類         WheelMaker wheelMaker = ExtensionLoader.getExtensionLoader(WheelMaker.class).getExtension(wheelMakerName);         // 4. 調(diào)用實(shí)現(xiàn)類的具體方法實(shí)現(xiàn)調(diào)用。         return wheelMaker.makeWheel(URL url);     } }

查看Adaptive注解源碼可知該注解可用在類或方法上,Adaptive 注解在類上或者方法上有不同的實(shí)現(xiàn)邏輯。

7.8.1 Adaptive 注解在類上

Adaptive 注解在類上時(shí),Dubbo 不會(huì)為該類生成代理類,Adaptive 注解在類上的情況很少,在 Dubbo 中,僅有兩個(gè)類被  Adaptive 注解了,分別是 AdaptiveCompiler 和  AdaptiveExtensionFactory,表示拓展的加載邏輯由人工編碼完成,這不是我們關(guān)注的重點(diǎn)。

7.8.2 Adaptive 注解在方法上

Adaptive 注解在方法上時(shí),Dubbo 則會(huì)為該方法生成代理邏輯,表示拓展的加載邏輯需由框架自動(dòng)生成,大致的實(shí)現(xiàn)機(jī)制如下:

加載標(biāo)注有 @Adaptive 注解的接口,如果不存在,則不支持 Adaptive 機(jī)制;

為目標(biāo)接口按照一定的模板生成子類代碼,并且編譯生成的代碼,然后通過(guò)反射生成該類的對(duì)象;

結(jié)合生成的對(duì)象實(shí)例,通過(guò)傳入的URL對(duì)象,獲取指定key的配置,然后加載該key對(duì)應(yīng)的類對(duì)象,最終將調(diào)用委托給該類對(duì)象進(jìn)行。

@SPI("apple") public interface FruitGranter {   Fruit grant();   @Adaptive   String watering(URL url); } --- // 蘋(píng)果種植者 public class AppleGranter implements FruitGranter {   @Override   public Fruit grant() {     return new Apple();   }   @Override   public String watering(URL url) {     System.out.println("watering apple");     return "watering finished";   } } --- // 香蕉種植者 public class BananaGranter implements FruitGranter {   @Override   public Fruit grant() {     return new Banana();   }   @Override   public String watering(URL url) {     System.out.println("watering banana");     return "watering success";   } }

調(diào)用方法實(shí)現(xiàn):

public class ExtensionLoaderTest {   @Test   public void testGetExtensionLoader() {     // 首先創(chuàng)建一個(gè)模擬用的URL對(duì)象     URL url = URL.valueOf("dubbo://192.168.0.1:1412?fruit.granter=apple");     // 通過(guò)ExtensionLoader獲取一個(gè)FruitGranter對(duì)象     FruitGranter granter = ExtensionLoader.getExtensionLoader(FruitGranter.class)       .getAdaptiveExtension();     // 使用該FruitGranter調(diào)用其"自適應(yīng)標(biāo)注的"方法,獲取調(diào)用結(jié)果     String result = granter.watering(url);     System.out.println(result);   } }

通過(guò)如上方式生成一個(gè)內(nèi)部類。大致調(diào)用流程如下:

關(guān)于Dubbo的問(wèn)題有哪些

4、Dubbo 服務(wù)暴露流程

4.1 服務(wù)暴露總覽

Dubbo框架是以URL為總線的模式,運(yùn)行過(guò)程中所有的狀態(tài)數(shù)據(jù)信息都可以通過(guò)URL來(lái)獲取,比如當(dāng)前系統(tǒng)采用什么序列化,采用什么通信,采用什么負(fù)載均衡等信息,都是通過(guò)URL的參數(shù)來(lái)呈現(xiàn)的,所以在框架運(yùn)行過(guò)程中,運(yùn)行到某個(gè)階段需要相應(yīng)的數(shù)據(jù),都可以通過(guò)對(duì)應(yīng)的Key從URL的參數(shù)列表中獲取。URL  具體的參數(shù)如下:

protocol:指的是 dubbo 中的各種協(xié)議,如:dubbo thrift http username/password:用戶名/密碼  host/port:主機(jī)/端口 path:接口的名稱 parameters:參數(shù)鍵值對(duì)

protocol://username:password@host:port/path?k=v

服務(wù)暴露從代碼流程看分為三部分:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 檢查配置,最終組裝成 URL。

  3. 暴露服務(wù)到到本地服務(wù)跟遠(yuǎn)程服務(wù)。

  4. 服務(wù)注冊(cè)至注冊(cè)中心。

服務(wù)暴露從對(duì)象構(gòu)建轉(zhuǎn)換看分為兩步:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 將服務(wù)封裝成Invoker。

  3. 將Invoker通過(guò)協(xié)議轉(zhuǎn)換為Exporter。

4.2 服務(wù)暴露源碼追蹤

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 容器啟動(dòng),Spring IOC 刷新完畢后調(diào)用 onApplicationEvent 開(kāi)啟服務(wù)暴露,ServiceBean 。

  3. export 跟 doExport 來(lái)進(jìn)行拼接構(gòu)建URL,為屏蔽調(diào)用的細(xì)節(jié),統(tǒng)一暴露出一個(gè)可執(zhí)行體,通過(guò)ProxyFactory 獲取到  invoker。

  4. 調(diào)用具體 Protocol 將把包裝后的 invoker 轉(zhuǎn)換成 exporter,此處用到了SPI。

  5. 然后啟動(dòng)服務(wù)器server,監(jiān)聽(tīng)端口,使用NettyServer創(chuàng)建監(jiān)聽(tīng)服務(wù)器。

  6. 通過(guò) RegistryProtocol 將URL注冊(cè)到注冊(cè)中心,使得consumer可獲得provider信息。圖片

5、Dubbo 服務(wù)引用流程

Dubbo中一個(gè)可執(zhí)行體就是一個(gè)invoker,所以 provider 跟 consumer 都要向 invoker  靠攏。通過(guò)上面demo可知為了無(wú)感調(diào)用遠(yuǎn)程接口,底層需要有個(gè)代理類包裝 invoker。

服務(wù)的引入時(shí)機(jī)有兩種:

餓漢式:

通過(guò)實(shí)現(xiàn) Spring 的 InitializingBean 接口中的 afterPropertiesSet 方法,容器通過(guò)調(diào)用  ReferenceBean的 afterPropertiesSet 方法時(shí)引入服務(wù)。

懶漢式(默認(rèn)):

懶漢式是只有當(dāng)服務(wù)被注入到其他類中時(shí)啟動(dòng)引入流程。

服務(wù)引用的三種方式:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 本地引入:服務(wù)暴露時(shí)本地暴露,避免網(wǎng)絡(luò)調(diào)用開(kāi)銷。

  3. 直接連接引入遠(yuǎn)程服務(wù):不啟動(dòng)注冊(cè)中心,直接寫(xiě)死遠(yuǎn)程Provider地址 進(jìn)行直連。

  4. 通過(guò)注冊(cè)中心引入遠(yuǎn)程服務(wù):通過(guò)注冊(cè)中心抉擇如何進(jìn)行負(fù)載均衡調(diào)用遠(yuǎn)程服務(wù)。

服務(wù)引用流程:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 檢查配置構(gòu)建map ,map 構(gòu)建 URL ,通過(guò)URL上的協(xié)議利用自適應(yīng)擴(kuò)展機(jī)制調(diào)用對(duì)應(yīng)的 protocol.refer 得到相應(yīng)的 invoker  ,此處

  3. 想注冊(cè)中心注冊(cè)自己,然后訂閱注冊(cè)中心相關(guān)信息,得到provider的 ip 等信息,再通過(guò)共享的netty客戶端進(jìn)行連接。

  4. 當(dāng)有多個(gè) URL 時(shí),先遍歷構(gòu)建出 invoker 然后再由 StaticDirectory 封裝一下,然后通過(guò) cluster 進(jìn)行合并,只暴露出一個(gè)  invoker 。

  5. 然后再構(gòu)建代理,封裝 invoker 返回服務(wù)引用,之后 Comsumer 調(diào)用的就是這個(gè)代理類。

關(guān)于Dubbo的問(wèn)題有哪些

調(diào)用方式:

oneway:不關(guān)心請(qǐng)求是否發(fā)送成功。

Async異步調(diào)用:Dubbo天然異步,客戶端調(diào)用請(qǐng)求后將返回的 ResponseFuture 存到上下文中,用戶可隨時(shí)調(diào)用 future.get  獲取結(jié)果。異步調(diào)用通過(guò)唯一ID 標(biāo)識(shí)此次請(qǐng)求。

Sync同步調(diào)用:在 Dubbo 源碼中就調(diào)用了 future.get,用戶感覺(jué)方法被阻塞了,必須等結(jié)果后才返回。

6、Dubbo 調(diào)用整體流程

調(diào)用之前你可能需要考慮這些事:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. consumer 跟 provider  約定好通訊協(xié)議,dubbo支持多種協(xié)議,比如dubbo、rmi、hessian、http、webservice等。默認(rèn)走dubbo協(xié)議,連接屬于單一長(zhǎng)連接,NIO異步通信。適用傳輸數(shù)據(jù)量很小(單次請(qǐng)求在100kb以內(nèi)),但是并發(fā)量很高。

  3. 約定序列化模式,大致分為兩大類,一種是字符型(XML或json 人可看懂 但傳輸效率低),一種是二進(jìn)制流(數(shù)據(jù)緊湊,機(jī)器友好)。默認(rèn)使用  hessian2作為序列化協(xié)議。

  4. consumer 調(diào)用 provider 時(shí)提供對(duì)應(yīng)接口、方法名、參數(shù)類型、參數(shù)值、版本號(hào)。

  5. provider列表對(duì)外提供服務(wù)涉及到負(fù)載均衡選擇一個(gè)provider提供服務(wù)。

  6. consumer 跟 provider 定時(shí)向monitor 發(fā)送信息。

調(diào)用大致流程:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 客戶端發(fā)起請(qǐng)求來(lái)調(diào)用接口,接口調(diào)用生成的代理類。代理類生成RpcInvocation 然后調(diào)用invoke方法。

  3. ClusterInvoker獲得注冊(cè)中心中服務(wù)列表,通過(guò)負(fù)載均衡給出一個(gè)可用的invoker。

  4. 序列化跟反序列化網(wǎng)絡(luò)傳輸數(shù)據(jù)。通過(guò)NettyServer調(diào)用網(wǎng)絡(luò)服務(wù)。

  5. 服務(wù)端業(yè)務(wù)線程池接受解析數(shù)據(jù),從exportMap找到invoker進(jìn)行invoke。

  6. 調(diào)用真正的Impl得到結(jié)果然后返回。

關(guān)于Dubbo的問(wèn)題有哪些

調(diào)用方式:

oneway:不關(guān)心請(qǐng)求是否發(fā)送成功,消耗最小。

sync同步調(diào)用:在 Dubbo 源碼中就調(diào)用了 future.get,用戶感覺(jué)方法被阻塞了,必須等結(jié)果后才返回。

Async 異步調(diào)用:Dubbo天然異步,客戶端調(diào)用請(qǐng)求后將返回的 ResponseFuture  存到上下文中,用戶可以隨時(shí)調(diào)用future.get獲取結(jié)果。異步調(diào)用通過(guò)唯一ID標(biāo)識(shí)此次請(qǐng)求。

7、Dubbo集群容錯(cuò)負(fù)載均衡

Dubbo  引入了Cluster、Directory、Router、LoadBalance、Invoker模塊來(lái)保證Dubbo系統(tǒng)的穩(wěn)健性,它們的關(guān)系如下圖:

關(guān)于Dubbo的問(wèn)題有哪些

服務(wù)發(fā)現(xiàn)時(shí)會(huì)將多個(gè)多個(gè)遠(yuǎn)程調(diào)用放入Directory,然后通過(guò)Cluster封裝成一個(gè)Invoker,該invoker提供容錯(cuò)功能。

消費(fèi)者代用的時(shí)候從Directory中通過(guò)負(fù)載均衡獲得一個(gè)可用invoker,最后發(fā)起調(diào)用。

你可以認(rèn)為Dubbo中的Cluster對(duì)上面進(jìn)行了大的封裝,自帶各種魯棒性功能。

7.1 集群容錯(cuò)

集群容錯(cuò)是在消費(fèi)者端通過(guò)Cluster子類實(shí)現(xiàn)的,Cluster接口有10個(gè)實(shí)現(xiàn)類,每個(gè)Cluster實(shí)現(xiàn)類都會(huì)創(chuàng)建一個(gè)對(duì)應(yīng)的ClusterInvoker對(duì)象。核心思想是讓用戶選擇性調(diào)用這個(gè)Cluster中間層,屏蔽后面具體實(shí)現(xiàn)細(xì)節(jié)。

ClusterCluster Invoker作用
FailoverClusterFailoverClusterInvoker失敗自動(dòng)切換功能,默認(rèn)
FailfastClusterFailfastClusterInvoker一次調(diào)用,失敗異常
FailsafeClusterFailsafeClusterInvoker調(diào)用出錯(cuò)則日志記錄
FailbackClusterFailbackClusterInvoker失敗返空,定時(shí)重試2次
ForkingClusterForkingClusterInvoker一個(gè)任務(wù)并發(fā)調(diào)用,一個(gè)OK則OK
BroadcastClusterBroadcastClusterInvoker逐個(gè)調(diào)用invoker,全可用才可用
AvailableClusterAvailableClusterInvoker哪個(gè)能用就用那個(gè)
MergeableClusterMergeableClusterInvoker按組合并返回結(jié)果

7.2 智能容錯(cuò)之負(fù)載均衡

Dubbo中一般有4種負(fù)載均衡策略。

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. RandomLoadBalance:加權(quán)隨機(jī),它的算法思想簡(jiǎn)單。假設(shè)有一組服務(wù)器 servers = [A, B, C],對(duì)應(yīng)權(quán)重為 weights =  [5, 3, 2],權(quán)重總和為10?,F(xiàn)把這些權(quán)重值平鋪在一維坐標(biāo)值上,[0, 5) 區(qū)間屬于服務(wù)器 A,[5, 8) 區(qū)間屬于服務(wù)器 B,[8, 10)  區(qū)間屬于服務(wù)器 C。接下來(lái)通過(guò)隨機(jī)數(shù)生成器生成一個(gè)范圍在 [0, 10) 之間的隨機(jī)數(shù),然后計(jì)算這個(gè)隨機(jī)數(shù)會(huì)落到哪個(gè)區(qū)間上。默認(rèn)實(shí)現(xiàn)。

  3. LeastActiveLoadBalance:最少活躍數(shù)負(fù)載均衡,選擇現(xiàn)在活躍調(diào)用數(shù)最少的提供者進(jìn)行調(diào)用,活躍的調(diào)用數(shù)少說(shuō)明它現(xiàn)在很輕松,而且活躍數(shù)都是從  0 加起來(lái)的,來(lái)一個(gè)請(qǐng)求活躍數(shù)+1,一個(gè)請(qǐng)求處理完成活躍數(shù)-1,所以活躍數(shù)少也能變相的體現(xiàn)處理的快。

  4. RoundRobinLoadBalance:加權(quán)輪詢負(fù)載均衡,比如現(xiàn)在有兩臺(tái)服務(wù)器 A、B,輪詢的調(diào)用順序就是 A、B、A、B,如果加了權(quán)重,A 比B  的權(quán)重是2:1,那現(xiàn)在的調(diào)用順序就是 A、A、B、A、A、B。

  5. ConsistentHashLoadBalance:一致性 Hash 負(fù)載均衡,將服務(wù)器的 IP 等信息生成一個(gè) hash 值,將hash  值投射到圓環(huán)上作為一個(gè)節(jié)點(diǎn),然后當(dāng) key 來(lái)查找的時(shí)候順時(shí)針查找第一個(gè)大于等于這個(gè) key 的 hash  值的節(jié)點(diǎn)。一般而言還會(huì)引入虛擬節(jié)點(diǎn),使得數(shù)據(jù)更加的分散,避免數(shù)據(jù)傾斜壓垮某個(gè)節(jié)點(diǎn)。如下圖 Dubbo 默認(rèn)搞了 160 個(gè)虛擬節(jié)點(diǎn)。圖片

關(guān)于Dubbo的問(wèn)題有哪些

7.3 智能容錯(cuò)之服務(wù)目錄

關(guān)于 服務(wù)目錄Directory 你可以理解為是相同服務(wù)Invoker的集合,核心是RegistryDirectory類。具有三個(gè)功能。

從注冊(cè)中心獲得invoker列表。

監(jiān)控著注冊(cè)中心invoker的變化,invoker的上下線。

刷新invokers列表到服務(wù)目錄。

7.4 智能容錯(cuò)之服務(wù)路由

服務(wù)路由其實(shí)就是路由規(guī)則,它規(guī)定了服務(wù)消費(fèi)者可以調(diào)用哪些服務(wù)提供者。條件路由規(guī)則由兩個(gè)條件組成,分別用于對(duì)服務(wù)消費(fèi)者和提供者進(jìn)行匹配。比如有這樣一條規(guī)則:

host = 10.20.153.14 => host = 10.20.153.12

該條規(guī)則表示 IP 為 10.20.153.14 的服務(wù)消費(fèi)者只可調(diào)用 IP 為 10.20.153.12  機(jī)器上的服務(wù),不可調(diào)用其他機(jī)器上的服務(wù)。條件路由規(guī)則的格式如下:

[服務(wù)消費(fèi)者匹配條件] => [服務(wù)提供者匹配條件]

如果服務(wù)消費(fèi)者匹配條件為空,表示不對(duì)服務(wù)消費(fèi)者進(jìn)行限制。如果服務(wù)提供者匹配條件為空,表示對(duì)某些服務(wù)消費(fèi)者禁用服務(wù)。

8、設(shè)計(jì)RPC

通讀下Dubbo的大致實(shí)現(xiàn)方式后其實(shí)就可以依葫蘆畫(huà)瓢了,一個(gè)RPC框架大致需要下面這些東西:

服務(wù)的注冊(cè)跟發(fā)現(xiàn)的搞一個(gè)吧,你可以用ZooKeeper或者redis來(lái)實(shí)現(xiàn)。

接下來(lái)consumer發(fā)起請(qǐng)求的時(shí)候你的面向接口編程啊,用到動(dòng)態(tài)代理來(lái)實(shí)現(xiàn)調(diào)用。

多個(gè)provider提供相同服務(wù)你的用到LoadBalance啊。

最終選擇一個(gè)機(jī)器后你的約定好通信協(xié)議啊,如何進(jìn)行序列化跟反序列化呢?

底層就用現(xiàn)成的高性能Netty框架 NIO模式實(shí)現(xiàn)唄。

服務(wù)開(kāi)啟后的有monitor啊。

感謝各位的閱讀,以上就是“關(guān)于Dubbo的問(wèn)題有哪些”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)關(guān)于Dubbo的問(wèn)題有哪些這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

當(dāng)前題目:關(guān)于Dubbo的問(wèn)題有哪些
鏈接地址:http://bm7419.com/article38/gighsp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供響應(yīng)式網(wǎng)站、網(wǎng)站收錄、網(wǎng)站改版虛擬主機(jī)、網(wǎng)站策劃Google

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

綿陽(yáng)服務(wù)器托管