精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

關(guān)于Dubbo隨便問八個(gè)問題

開發(fā) 前端
互聯(lián)網(wǎng)公司的系統(tǒng)有成千上萬個(gè)大大小小的服務(wù)組成,服務(wù)各自部署在不同的機(jī)器上,服務(wù)間的調(diào)用需要用到網(wǎng)絡(luò)通信,服務(wù)消費(fèi)方每調(diào)用一個(gè)服務(wù)都要寫一坨網(wǎng)絡(luò)通信相關(guān)的代碼,不僅復(fù)雜而且極易出錯(cuò)。

[[374925]]

本文轉(zhuǎn)載自微信公眾號(hào)「sowhat1412 」,作者sowhat1412 。轉(zhuǎn)載本文請(qǐng)聯(lián)系sowhat1412 公眾號(hào)。   

1、RPC

1.1 RPC 定義

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

RPC:

Remote Procedure Call Protocol 既 遠(yuǎn)程過程調(diào)用,一種能讓我們像調(diào)用本地服務(wù)一樣調(diào)用遠(yuǎn)程服務(wù),可以讓調(diào)用者對(duì)網(wǎng)絡(luò)通信這些細(xì)節(jié)無感知,比如服務(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

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

1.2.1 公共接口

  1. public interface SoWhatService { 
  2.     String sayHello(String name);   
  3. }  

1.2.2 服務(wù)提供者

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

  1. public class SoWhatServiceImpl implements SoWhatService 
  2.  @Override 
  3.  public String sayHello(String name
  4.  { 
  5.   return "你好啊 " + name
  6.  } 
  7. }   

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

  1. /** 
  2.  * 服務(wù)注冊(cè)對(duì)外提供者 
  3.  */ 
  4.  
  5. public class ServiceFramework 
  6.  public static void export(Object service, int port) throws Exception 
  7.  { 
  8.   ServerSocket server = new ServerSocket(port); 
  9.   while (true
  10.   { 
  11.    Socket socket = server.accept(); 
  12.    new Thread(() -> 
  13.    { 
  14.     try 
  15.     { 
  16.      //反序列化 
  17.      ObjectInputStream input = new ObjectInputStream(socket.getInputStream()); 
  18.      //讀取方法名 
  19.      String methodName =(String) input.readObject(); 
  20.      //參數(shù)類型 
  21.      Class<?>[] parameterTypes = (Class<?>[]) input.readObject(); 
  22.      //參數(shù) 
  23.      Object[] arguments = (Object[]) input.readObject(); 
  24.      //找到方法 
  25.      Method method = service.getClass().getMethod(methodName, parameterTypes); 
  26.      //調(diào)用方法 
  27.      Object result = method.invoke(service, arguments); 
  28.      // 返回結(jié)果 
  29.      ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream()); 
  30.      output.writeObject(result); 
  31.     } catch (Exception e) 
  32.     { 
  33.      e.printStackTrace(); 
  34.     } 
  35.    }).start(); 
  36.   } 
  37.  } 

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

  1. public class ServerMain 
  2.  public static void main(String[] args) 
  3.  { 
  4.   //服務(wù)提供者 暴露出接口 
  5.   SoWhatService service = new SoWhatServiceImpl(); 
  6.   try 
  7.   { 
  8.    ServiceFramework.export(service, 1412); 
  9.   } catch (Exception e) 
  10.   { 
  11.    e.printStackTrace(); 
  12.   } 
  13.  } 

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

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

  1. /** 
  2.  * @author sowhat 
  3.  * 動(dòng)態(tài)代理調(diào)用遠(yuǎn)程服務(wù) 
  4.  */ 
  5. public class RpcFunction 
  6.  public static <T> T refer(Class<T> interfaceClass, String host, int port) throws Exception 
  7.  { 
  8.   return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[]{interfaceClass}, 
  9.     new InvocationHandler() 
  10.     { 
  11.      @Override 
  12.      public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable 
  13.      { 
  14.       //指定 provider 的 ip 和端口 
  15.       Socket socket = new Socket(host, port); 
  16.       ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream()); 
  17.       //傳方法名 
  18.       output.writeObject(method.getName()); 
  19.       //傳參數(shù)類型 
  20.       output.writeObject(method.getParameterTypes()); 
  21.       //傳參數(shù)值 
  22.       output.writeObject(arguments); 
  23.       ObjectInputStream input = new ObjectInputStream(socket.getInputStream()); 
  24.       //讀取結(jié)果 
  25.       Object result = input.readObject(); 
  26.       return result; 
  27.      } 
  28.     }); 
  29.  } 

調(diào)用方法

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

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

2.1 Dubbo 簡(jiǎn)介

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

調(diào)用過程:

  1. 服務(wù)提供者 Provider 啟動(dòng)然后向 Registry 注冊(cè)自己所能提供的服務(wù)。
  2. 服務(wù)消費(fèi)者 Consumer 向Registry訂閱所需服務(wù),Consumer 解析Registry提供的元信息,從服務(wù)中通過負(fù)載均衡選擇 Provider調(diào)用。
  3. 服務(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 是可選的,可直接在配置文件中寫好,Provider 跟 Consumer進(jìn)行直連。

Monitor 跟 Registry 掛了也沒事, Consumer 本地緩存了 Provider 信息。

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

2.2 Dubbo框架分層

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

  1. Busines層:由用戶自己來提供接口和實(shí)現(xiàn)還有一些配置信息。
  2. RPC層:真正的RPC調(diào)用的核心層,封裝整個(gè)RPC的調(diào)用過程、負(fù)載均衡、集群容錯(cuò)、代理。
  3. Remoting層:對(duì)網(wǎng)絡(luò)傳輸協(xié)議和數(shù)據(jù)轉(zhuǎn)換的封裝。

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

  1. 接口服務(wù)層(Service):該層與業(yè)務(wù)邏輯相關(guān),根據(jù) provider 和 consumer 的業(yè)務(wù)設(shè)計(jì)對(duì)應(yīng)的接口和實(shí)現(xiàn)。
  2. 配置層(Config):對(duì)外配置接口,以 ServiceConfig 和 ReferenceConfig 為中心初始化配置。
  3. 服務(wù)代理層(Proxy):服務(wù)接口透明代理,Provider跟Consumer都生成代理類,使得服務(wù)接口透明,代理層實(shí)現(xiàn)服務(wù)調(diào)用跟結(jié)果返回。
  4. 服務(wù)注冊(cè)層(Registry):封裝服務(wù)地址的注冊(cè)和發(fā)現(xiàn),以服務(wù) URL 為中心。
  5. 路由層(Cluster):封裝多個(gè)提供者的路由和負(fù)載均衡,并橋接注冊(cè)中心,以Invoker 為中心,擴(kuò)展接口為 Cluster、Directory、Router 和 LoadBlancce。
  6. 監(jiān)控層(Monitor):RPC 調(diào)用次數(shù)和調(diào)用時(shí)間監(jiān)控,以 Statistics 為中心,擴(kuò)展接口為 MonitorFactory、Monitor 和 MonitorService。
  7. 遠(yuǎn)程調(diào)用層(Protocal):封裝 RPC 調(diào)用,以 Invocation 和 Result 為中心,擴(kuò)展接口為 Protocal、Invoker 和 Exporter。
  8. 信息交換層(Exchange):封裝請(qǐng)求響應(yīng)模式,同步轉(zhuǎn)異步。以 Request 和Response 為中心,擴(kuò)展接口為 Exchanger、ExchangeChannel、ExchangeClient 和 ExchangeServer。
  9. 網(wǎng)絡(luò)傳輸層(Transport):抽象 mina 和 netty 為統(tǒng)一接口,以 Message 為中心,擴(kuò)展接口為 Channel、Transporter、Client、Server 和 Codec。
  10. 數(shù)據(jù)序列化層(Serialize):可復(fù)用的一些工具,擴(kuò)展接口為 Serialization、ObjectInput、ObjectOutput 和 ThreadPool。

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

3、Dubbo SPI 機(jī)制

Dubbo 采用 微內(nèi)核設(shè)計(jì) + SPI 擴(kuò)展技術(shù)來搭好核心框架,同時(shí)滿足用戶定制化需求。這里重點(diǎn)說下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)核來實(shí)現(xiàn),而微內(nèi)核則僅保留最基礎(chǔ)的功能,Linux 就是宏內(nèi)核架構(gòu)設(shè)計(jì)。

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

思想是 核心系統(tǒng) + 插件,說白了就是把不變的功能抽象出來稱為核心,把變動(dòng)的功能作為插件來擴(kuò)展,符合開閉原則,更容易擴(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ù)是不同公司開發(fā)的,它們的底層協(xié)議不大一樣,那怎么約束呢?一般就是定制統(tǒng)一接口,具體實(shí)現(xiàn)不管,反正面向相同的接口編程即可。等到真正使用的時(shí)候用具體的實(shí)現(xiàn)類就好,問題是哪里找用那個(gè)實(shí)現(xiàn)類呢?這時(shí)候就采用約定好的法則將實(shí)現(xiàn)類寫到指定位置即可。

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

3.3 SPI demo

接口:

  1. package com.example.demo.spi; 
  2.  
  3. public interface SPIService { 
  4.     void execute(); 

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

  1. public class SpiImpl1 implements SPIService{ 
  2.  @Override 
  3.     public void execute() { 
  4.         System.out.println("SpiImpl1.execute()"); 
  5.     } 

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

  1. public class SpiImpl2 implements SPIService{ 
  2.  @Override 
  3.     public void execute() { 
  4.   System.out.println("SpiImpl2.execute()"); 
  5.     } 

配置路徑

調(diào)用加載類

  1. package com.example.demo.spi; 
  2. import sun.misc.Service; 
  3. import java.util.Iterator; 
  4. import java.util.ServiceLoader; 
  5.  
  6. public class Test { 
  7.     public static void main(String[] args) {     
  8.         Iterator<SPIService> providers = Service.providers(SPIService.class); 
  9.         ServiceLoader<SPIService> load = ServiceLoader.load(SPIService.class); 
  10.  
  11.         while(providers.hasNext()) { 
  12.             SPIService ser = providers.next(); 
  13.             ser.execute(); 
  14.         } 
  15.         System.out.println("--------------------------------"); 
  16.         Iterator<SPIService> iterator = load.iterator(); 
  17.         while(iterator.hasNext()) { 
  18.             SPIService ser = iterator.next(); 
  19.             ser.execute(); 
  20.         } 
  21.     } 

3.4 SPI源碼追蹤

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

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)類的方式不夠靈活,只能通過 Iterator 形式獲取,不能根據(jù)某個(gè)參數(shù)來獲取對(duì)應(yīng)的實(shí)現(xiàn)類。

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

3.6 Dubbo SPI

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

  1. key = com.sowhat.value 

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

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

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

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

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

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

3.7 Dubbo SPI源碼追蹤

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

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

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

查看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)接口按照一定的模板生成子類代碼,并且編譯生成的代碼,然后通過反射生成該類的對(duì)象;

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

  1. @SPI("apple"
  2. public interface FruitGranter { 
  3.   Fruit grant(); 
  4.   @Adaptive 
  5.   String watering(URL url); 
  6. --- 
  7. // 蘋果種植者 
  8. public class AppleGranter implements FruitGranter { 
  9.   @Override 
  10.   public Fruit grant() { 
  11.     return new Apple(); 
  12.   } 
  13.   @Override 
  14.   public String watering(URL url) { 
  15.     System.out.println("watering apple"); 
  16.     return "watering finished"
  17.   } 
  18. --- 
  19. // 香蕉種植者 
  20. public class BananaGranter implements FruitGranter { 
  21.   @Override 
  22.   public Fruit grant() { 
  23.     return new Banana(); 
  24.   } 
  25.   @Override 
  26.   public String watering(URL url) { 
  27.     System.out.println("watering banana"); 
  28.     return "watering success"
  29.   } 

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

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

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

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

4.1 服務(wù)暴露總覽

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

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

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

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

  1. 檢查配置,最終組裝成 URL。
  2. 暴露服務(wù)到到本地服務(wù)跟遠(yuǎn)程服務(wù)。
  3. 服務(wù)注冊(cè)至注冊(cè)中心。

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

  1. 將服務(wù)封裝成Invoker。
  2. 將Invoker通過協(xié)議轉(zhuǎn)換為Exporter。

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

  1. 容器啟動(dòng),Spring IOC 刷新完畢后調(diào)用 onApplicationEvent 開啟服務(wù)暴露,ServiceBean 。
  2. export 跟 doExport 來進(jìn)行拼接構(gòu)建URL,為屏蔽調(diào)用的細(xì)節(jié),統(tǒng)一暴露出一個(gè)可執(zhí)行體,通過ProxyFactory 獲取到 invoker。
  3. 調(diào)用具體 Protocol 將把包裝后的 invoker 轉(zhuǎn)換成 exporter,此處用到了SPI。
  4. 然后啟動(dòng)服務(wù)器server,監(jiān)聽端口,使用NettyServer創(chuàng)建監(jiān)聽服務(wù)器。
  5. 通過 RegistryProtocol 將URL注冊(cè)到注冊(cè)中心,使得consumer可獲得provider信息。圖片

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

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

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

餓漢式:

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

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

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

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

  1. 本地引入:服務(wù)暴露時(shí)本地暴露,避免網(wǎng)絡(luò)調(diào)用開銷。
  2. 直接連接引入遠(yuǎn)程服務(wù):不啟動(dòng)注冊(cè)中心,直接寫死遠(yuǎn)程Provider地址 進(jìn)行直連。
  3. 通過注冊(cè)中心引入遠(yuǎn)程服務(wù):通過注冊(cè)中心抉擇如何進(jìn)行負(fù)載均衡調(diào)用遠(yuǎn)程服務(wù)。

服務(wù)引用流程:

  1. 檢查配置構(gòu)建map ,map 構(gòu)建 URL ,通過URL上的協(xié)議利用自適應(yīng)擴(kuò)展機(jī)制調(diào)用對(duì)應(yīng)的 protocol.refer 得到相應(yīng)的 invoker ,此處
  2. 想注冊(cè)中心注冊(cè)自己,然后訂閱注冊(cè)中心相關(guān)信息,得到provider的 ip 等信息,再通過共享的netty客戶端進(jìn)行連接。
  3. 當(dāng)有多個(gè) URL 時(shí),先遍歷構(gòu)建出 invoker 然后再由 StaticDirectory 封裝一下,然后通過 cluster 進(jìn)行合并,只暴露出一個(gè) invoker 。
  4. 然后再構(gòu)建代理,封裝 invoker 返回服務(wù)引用,之后 Comsumer 調(diào)用的就是這個(gè)代理類。

 

調(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)用通過唯一ID 標(biāo)識(shí)此次請(qǐng)求。

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

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

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

  1. 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ā)量很高。
  2. 約定序列化模式,大致分為兩大類,一種是字符型(XML或json 人可看懂 但傳輸效率低),一種是二進(jìn)制流(數(shù)據(jù)緊湊,機(jī)器友好)。默認(rèn)使用 hessian2作為序列化協(xié)議。
  3. consumer 調(diào)用 provider 時(shí)提供對(duì)應(yīng)接口、方法名、參數(shù)類型、參數(shù)值、版本號(hào)。
  4. provider列表對(duì)外提供服務(wù)涉及到負(fù)載均衡選擇一個(gè)provider提供服務(wù)。
  5. consumer 跟 provider 定時(shí)向monitor 發(fā)送信息。

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

  1. 客戶端發(fā)起請(qǐng)求來調(diào)用接口,接口調(diào)用生成的代理類。代理類生成RpcInvocation 然后調(diào)用invoke方法。
  2. ClusterInvoker獲得注冊(cè)中心中服務(wù)列表,通過負(fù)載均衡給出一個(gè)可用的invoker。
  3. 序列化跟反序列化網(wǎng)絡(luò)傳輸數(shù)據(jù)。通過NettyServer調(diào)用網(wǎng)絡(luò)服務(wù)。
  4. 服務(wù)端業(yè)務(wù)線程池接受解析數(shù)據(jù),從exportMap找到invoker進(jìn)行invoke。
  5. 調(diào)用真正的Impl得到結(jié)果然后返回。

調(diào)用方式:

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

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

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

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

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

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

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

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

7.1 集群容錯(cuò)

集群容錯(cuò)是在消費(fèi)者端通過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é)。

Cluster Cluster Invoker 作用
FailoverCluster FailoverClusterInvoker 失敗自動(dòng)切換功能,默認(rèn)
FailfastCluster FailfastClusterInvoker 一次調(diào)用,失敗異常
FailsafeCluster FailsafeClusterInvoker 調(diào)用出錯(cuò)則日志記錄
FailbackCluster FailbackClusterInvoker 失敗返空,定時(shí)重試2次
ForkingCluster ForkingClusterInvoker 一個(gè)任務(wù)并發(fā)調(diào)用,一個(gè)OK則OK
BroadcastCluster BroadcastClusterInvoker 逐個(gè)調(diào)用invoker,全可用才可用
AvailableCluster AvailableClusterInvoker 哪個(gè)能用就用那個(gè)
MergeableCluster MergeableClusterInvoker 按組合并返回結(jié)果

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

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

  1. RandomLoadBalance:加權(quán)隨機(jī),它的算法思想簡(jiǎn)單。假設(shè)有一組服務(wù)器 servers = [A, B, C],對(duì)應(yīng)權(quán)重為 weights = [5, 3, 2],權(quán)重總和為10。現(xiàn)把這些權(quán)重值平鋪在一維坐標(biāo)值上,[0, 5) 區(qū)間屬于服務(wù)器 A,[5, 8) 區(qū)間屬于服務(wù)器 B,[8, 10) 區(qū)間屬于服務(wù)器 C。接下來通過隨機(jī)數(shù)生成器生成一個(gè)范圍在 [0, 10) 之間的隨機(jī)數(shù),然后計(jì)算這個(gè)隨機(jī)數(shù)會(huì)落到哪個(gè)區(qū)間上。默認(rèn)實(shí)現(xiàn)。
  2. LeastActiveLoadBalance:最少活躍數(shù)負(fù)載均衡,選擇現(xiàn)在活躍調(diào)用數(shù)最少的提供者進(jìn)行調(diào)用,活躍的調(diào)用數(shù)少說明它現(xiàn)在很輕松,而且活躍數(shù)都是從 0 加起來的,來一個(gè)請(qǐng)求活躍數(shù)+1,一個(gè)請(qǐng)求處理完成活躍數(shù)-1,所以活躍數(shù)少也能變相的體現(xiàn)處理的快。
  3. 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。
  4. ConsistentHashLoadBalance:一致性 Hash 負(fù)載均衡,將服務(wù)器的 IP 等信息生成一個(gè) hash 值,將hash 值投射到圓環(huán)上作為一個(gè)節(jié)點(diǎn),然后當(dāng) key 來查找的時(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)。圖片

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ī)則:

  1. 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ī)則的格式如下:

  1. [服務(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í)就可以依葫蘆畫瓢了,一個(gè)RPC框架大致需要下面這些東西:

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

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

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

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

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

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

PS :

感覺沒啥特別好寫的,因?yàn)槿薉ubbo官方文檔啥都有,你說你英文看不懂,那中文總該看得懂了吧。

參考

Dubbo面試題:https://sowhat.blog.csdn.net/article/details/71191035

Adaptive講解:https://blog.csdn.net/weixin_33967071/article/details/92608993 Dubbo視頻:https://b23.tv/KVk0xo

Dubbo demo:https://mp.weixin.qq.com/s/FPbu8rFOHyTGROIV8XJeTA doExportUrlsFor1Protocol詳解:https://www.cnblogs.com/hzhuxin/p/7993860.html

 

責(zé)任編輯:武曉燕 來源: sowhat1412
相關(guān)推薦

2023-02-22 14:50:59

技術(shù)AI

2024-03-06 13:56:00

項(xiàng)目awaitpromise

2025-02-07 15:01:49

Promise數(shù)組前端

2014-06-17 09:51:57

Docker

2024-01-02 16:16:34

Promise前端

2019-11-27 11:06:30

災(zāi)難DDoS勒索軟件

2009-03-26 09:39:16

CSS網(wǎng)頁布局

2010-09-27 13:41:49

TCP IP故障問題

2023-08-09 14:01:55

2022-11-04 15:37:04

產(chǎn)品策略開發(fā)競(jìng)爭(zhēng)

2012-10-15 09:36:23

2023-05-18 14:06:51

人工智能AI

2019-10-18 15:16:10

Redis數(shù)據(jù)庫(kù)并發(fā)

2010-08-31 10:49:16

CSS網(wǎng)頁布局

2009-12-04 15:33:42

安裝Windows 7

2022-12-01 16:53:27

NPM技巧

2023-10-10 10:27:37

DevOps

2012-10-29 11:01:17

2017-01-05 09:59:45

2017-04-20 12:51:28

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

日本999视频| 含羞草久久爱69一区| 国产黄色录像视频| 久久视频免费| 日韩欧美国产成人| 国产又黄又爽免费视频| 日韩一级片免费看| 蜜臀久久99精品久久久久宅男| 日韩在线免费观看视频| 911亚洲精选| 亚洲日本在线观看视频| 一区二区国产盗摄色噜噜| 久久综合入口| 亚洲精品一区二区三区不卡| 日韩高清不卡一区二区三区| 欧美日韩不卡合集视频| 三上悠亚影音先锋| caoporn成人| 欧美美女直播网站| www.com毛片| 日本伦理一区二区| 国产欧美日韩久久| 国内精品二区| www香蕉视频| 美国一区二区三区在线播放 | 日本美女一区二区三区| 性色av一区二区咪爱| 女同久久另类69精品国产| 日韩三级毛片| 欧美成人精精品一区二区频| 色婷婷.com| 在线国产成人影院| 婷婷丁香激情综合| 日韩精品综合在线| 高清全集视频免费在线| 国产精品免费久久久久| 青娱乐国产91| 免费黄色在线视频网站| www.av亚洲| 成人xxxxx色| www.国产麻豆| 国产乱人伦偷精品视频免下载| 国产精品久久久久9999| 国产污视频网站| 一区二区三区福利| 久久久久久亚洲精品不卡| 日韩国产第一页| 五月久久久综合一区二区小说| 亚洲欧洲美洲在线综合| 免费看污黄网站在线观看| 欧美a一欧美| 日韩高清av在线| 日韩免费高清一区二区| 久久香蕉网站| 精品视频在线观看日韩| 波多野结衣福利| 欧美午夜寂寞| 亚洲男人的天堂网站| 久久久久久九九九九九| 国产精品日韩精品中文字幕| 亚洲欧美国产一本综合首页| 97伦伦午夜电影理伦片| 精品久久国产| 精品国产依人香蕉在线精品| 国产成人av免费在线观看| 亚洲国产成人精品女人| 久久成人av网站| 麻豆chinese极品少妇| 韩国av一区| 97视频在线观看成人| 五月婷婷色丁香| 日本伊人精品一区二区三区观看方式| 国产精品91在线观看| 中文在线免费看视频| 国产一区二区三区黄视频 | 在线中文资源天堂| 日韩一区日韩二区| 日韩免费在线观看av| 国产白浆在线免费观看| 日韩欧美在线网址| 午夜免费福利视频在线观看| 欧美午夜在线播放| 亚洲电影第1页| 亚洲理论片在线观看| 性xxxx欧美老肥妇牲乱| 欧美激情视频一区二区三区不卡| 日韩手机在线观看| 秋霞电影一区二区| 99久久伊人精品影院| 国产在线自天天| 亚洲日本青草视频在线怡红院 | 欧美一区二区三区在线播放 | 日日干夜夜操s8| 日韩一区二区三区色| 亚洲精品视频播放| 国产日产在线观看| 亚洲另类黄色| 国产一区红桃视频| 欧美男男同志| 亚洲精品高清视频在线观看| 日本www在线播放| 91精品国产色综合久久不卡粉嫩| 亚洲国产精品女人久久久| 在线观看免费小视频| 中文字幕免费一区二区| 欧美在线一级视频| 性一交一乱一精一晶| 国产性色一区二区| 可以看毛片的网址| 亚洲热av色在线播放| 精品网站999www| 久久久久人妻一区精品色欧美| 日本欧美加勒比视频| 精品国产乱码久久久久久蜜柚 | 欧美精美视频| 久久久久久久色| 国产精品丝袜黑色高跟鞋| 久久综合色播五月| 日韩欧美不卡在线| 看亚洲a级一级毛片| 中文字幕精品久久久久| 国产微拍精品一区| 高清不卡在线观看| 欧洲xxxxx| a∨色狠狠一区二区三区| 日韩av网站大全| 久久久久久国产精品免费播放| 麻豆精品国产91久久久久久| 欧美日韩国产一二| 福利在线免费视频| 精品日韩在线一区| 朝桐光av在线| 美女网站色91| 日韩av电影免费播放| 中国色在线日|韩| 亚洲国产精品久久91精品| 欧美日韩在线观看成人| 精品一区二区三区免费视频| 日产精品高清视频免费| 88xx成人免费观看视频库| 日韩黄色在线免费观看| 国产手机在线视频| 99久久精品免费看国产| 国产美女在线一区| www.成人网| 久久久久久久久久久免费 | 成人综合在线网站| 成人黄色片免费| 中文字幕日韩高清在线| 欧美成人一二三| www.激情五月| 亚洲午夜精品久久久久久久久| 可以看的av网址| 国产精品激情电影| 国产精品手机在线| 老司机深夜福利在线观看| 亚洲成人精品视频在线观看| 欧美三级韩国三级日本三斤在线观看| 成人免费av资源| av在线播放亚洲| 亚洲a级精品| 国产精品久久久久久亚洲影视| yiren22综合网成人| 欧美日韩精品一区二区在线播放| 婷婷丁香综合网| 国产真实乱偷精品视频免| 欧美交换配乱吟粗大25p| 8848成人影院| 欧美一级免费视频| av在线日韩国产精品| 欧美日本一道本| 欧美日韩在线国产| 97se亚洲国产综合自在线| 日韩a在线播放| 日本一区二区在线看| 亚洲va欧美va国产综合剧情 | 91tv官网精品成人亚洲| 国产精品有限公司| 黄瓜视频成人app免费| 久久精品成人一区二区三区| 亚洲男人第一天堂| 色综合天天综合在线视频| 精品在线观看一区| 成人高清在线视频| 欧美日韩在线观看不卡| 中文字幕乱码亚洲无线精品一区 | 中文字幕第六页| 国产精品久久777777毛茸茸| 亚洲精品日韩在线观看| 亚洲小说春色综合另类电影| 日本精品久久中文字幕佐佐木| 91caoporn在线| 亚洲精品一区二区三区精华液 | 日韩二区三区四区| 亚洲啊啊啊啊啊| 精品高清久久| 国产福利久久| 欧美网站免费| 国模叶桐国产精品一区| 亚洲一区二区三区无码久久| 免费一区视频| 影音先锋成人资源网站| 黄色成人美女网站| 成人免费直播live| 天天综合av| 久久6精品影院| 成人欧美一区| 日韩精品免费综合视频在线播放 | 精品国产自在久精品国产| 91麻豆精品在线| 亚洲成人免费视频| 九九热最新地址| 日本一区二区视频在线观看| 中文字幕天堂av| 极品少妇一区二区| 欧美国产日韩在线播放| 在线观看一区视频| 日本xxx免费| 久久免费大视频| 欧美aaaaa喷水| 精品精品国产毛片在线看| 成人午夜一级二级三级| 国产成人精品123区免费视频| 97人人做人人爱| 影院在线观看全集免费观看| 自拍偷拍亚洲一区| 国产黄色在线| 亚洲欧美日韩成人| 亚洲av成人精品一区二区三区在线播放 | 日批免费在线观看| 欧美一区二区精品久久911| 亚洲国产无线乱码在线观看| 欧美天堂在线观看| 中日韩精品视频在线观看| 亚洲国产乱码最新视频| 免费视频一二三区| 亚洲综合自拍偷拍| 欧美爱爱小视频| 亚洲欧美国产毛片在线| 91免费公开视频| 亚洲丝袜自拍清纯另类| 尤物在线免费视频| 亚洲卡通动漫在线| 欧美黑人性猛交xxx| 亚洲色图第一区| 看免费黄色录像| 亚洲女与黑人做爰| 欧美 日韩 国产 一区二区三区| 一色桃子久久精品亚洲| 天天色影综合网| 亚洲精品中文字幕在线观看| 麻豆精品一区二区三区视频| 亚洲综合一区二区精品导航| 久久久国产精品黄毛片| 亚洲一区av在线| 成年免费在线观看| 色综合久久久久综合体| 日韩久久久久久久久久| 欧美日韩久久久| 国产精品视频第一页| 精品久久久久一区| 日本人妻丰满熟妇久久久久久| 日韩精品视频三区| 国产美女视频一区二区三区| 在线观看日韩av| 老司机福利在线视频| 欧美日本在线视频中文字字幕| 99爱在线观看| 国产97色在线| 亚洲国产伊人| 国产高清在线一区| 伊人久久大香线蕉| 国产又爽又黄ai换脸| 国产精品videosex极品| 欧美精品99久久| 裸体一区二区三区| 涩视频在线观看| 国产亚洲一区二区三区四区| 国产成人免费在线观看视频| 亚洲激情自拍视频| 中文字幕视频网| 这里只有精品免费| 污污视频在线免费看| 最近中文字幕mv在线一区二区三区四区 | 最新中文字幕第一页| 欧美一区二区三区视频免费播放 | 久久亚洲成人精品| 深夜av在线| 成人网在线观看| 欧美18免费视频| 自拍偷拍视频在线| 免费日韩视频| 日韩高清在线一区二区| 91农村精品一区二区在线| 黑人操日本美女| 五月天亚洲婷婷| 国产精品羞羞答答在线| 日韩精品中文在线观看| 成人在线网址| 国产精品白嫩美女在线观看| 亚洲网一区二区三区| 亚洲 日韩 国产第一区| 影音先锋久久资源网| 欧美一级特黄a| www.久久久久久久久| 91视频综合网| 欧美日韩一卡二卡| 日本1级在线| 欧美激情亚洲激情| 国产电影一区| 亚洲国产精品一区二区第四页av| 亚洲国产免费看| 97超碰人人看| 国产精品区一区二区三区| 欧美三级韩国三级日本三斤在线观看| 91麻豆精品久久久久蜜臀| 国产三级在线观看| 91国内精品久久| 最新超碰在线| 国产精品一区二区久久久 | 成年人三级视频| 蜜臀av一区二区在线免费观看| 人妻精品久久久久中文字幕| 亚洲一级不卡视频| 亚洲成人一二三区| 久久这里只有精品视频首页| av在线不卡精品| 欧美日韩亚洲一区二区三区在线观看| 黄色欧美成人| 日韩黄色一区二区| 一区二区三区精品视频在线| 国产又爽又黄免费软件| 日韩在线免费高清视频| 国产精品亚洲成在人线| 亚洲精品二区| 免费一级片91| xxxxx99| 欧美日韩国产综合草草| 91社区在线高清| 国产日韩av高清| 亚洲天堂免费| 18深夜在线观看免费视频| 亚洲精品国产无套在线观| 精品人妻无码一区二区色欲产成人 | 欧美videos另类精品| 超碰97人人人人人蜜桃| 欧美福利电影在线观看| 国产成人精品一区二区在线小狼| 亚洲欧洲综合另类| 国产高清免费观看| 国内成人精品一区| 欧美日韩导航| www.国产区| 国产精品蜜臀在线观看| 一区二区的视频| 中文字幕亚洲欧美在线| 婷婷丁香久久| 乱熟女高潮一区二区在线| 粉嫩av亚洲一区二区图片| 国产成人愉拍精品久久| 精品伊人久久97| 色猫猫成人app| 91视频成人免费| 成人av免费在线| 中文人妻av久久人妻18| 中文字幕精品视频| 日韩区一区二| 日批视频在线免费看| 亚洲国产精品成人久久综合一区| 91欧美日韩麻豆精品| 欧美激情久久久久| 视频一区欧美| av噜噜在线观看| 天天影视网天天综合色在线播放| 免费在线视频一级不卡| 国产美女直播视频一区| 欧美福利网址| 国产jjizz一区二区三区视频| 欧美日韩免费一区二区三区视频| 视频在线观看入口黄最新永久免费国产 | 综合网日日天干夜夜久久| 国产一区二区三区黄网站| 黄色一级视频在线播放| 欧美韩日一区二区三区四区| 国产精品美女一区| 欧美亚洲国产视频| 97精品一区二区| 在线观看国产网站| 欧美日韩国产综合视频在线观看| 超碰在线99| 一区二区av| 91免费版在线看| 一级α片免费看刺激高潮视频| 欧美激情亚洲自拍| 日产午夜精品一线二线三线| 欧亚乱熟女一区二区在线| 精品视频免费在线| sm性调教片在线观看 | 亚洲第一香蕉网| 欧美一区二区国产|