精品欧美一区二区三区在线观看 _久久久久国色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)

欧美一级理论片| 国产成人在线网站| 亚洲一区www| 色18美女社区| 美女91在线看| 国产精品看片你懂得| 日韩毛片在线免费看| 久操视频免费在线观看| 欧美三级午夜理伦三级小说| 色噜噜狠狠色综合中国| 欧美爱爱视频网站| 深夜福利视频网站| 美腿丝袜亚洲一区| 隔壁老王国产在线精品| 性の欲びの女javhd| 一区二区三区亚洲变态调教大结局| 性做久久久久久免费观看欧美| 日韩国产精品一区二区| www.黄色国产| 日本成人在线电影网| 久久久综合av| 羞羞在线观看视频| 欧美日韩大片免费观看| 91精品中文字幕一区二区三区| 成人一区二区免费视频| 黄色网在线免费观看| 久久综合一区二区| 国产二区一区| 国产男男gay网站| 日韩精品91亚洲二区在线观看| 久久久亚洲网站| 国产美女福利视频| 欧美mv日韩| 亚洲欧美三级伦理| 亚洲偷熟乱区亚洲香蕉av| 蜜桃999成人看片在线观看| 国产伦理一区二区| 日韩1区2区日韩1区2区| 91精品国产91久久久久久吃药| 国内毛片毛片毛片毛片毛片| 国产免费av一区二区三区| 亚洲国产成人精品久久| 可以看的av网址| 国产精品久久久久久久久久久久久久久 | 久久av国产紧身裤| 欧美成人aa大片| 三级网站免费看| 成人免费观看49www在线观看| 在线观看www91| 任你操这里只有精品| 少妇视频一区| 色偷偷久久人人79超碰人人澡| 免费看毛片的网址| 久草免费在线色站| 一区二区成人在线视频| 成人区一区二区| 午夜小视频在线观看| 有坂深雪av一区二区精品| 精品国产一区二区三区在线| 欧美日本高清| 最近日韩中文字幕| 久久国产精品免费观看| 伊人福利在线| 亚洲国产日韩在线一区模特| 免费av手机在线观看| 九九精品调教| 亚洲高清久久久| 男人日女人逼逼| 综合日韩av| 色噜噜狠狠成人中文综合| av视屏在线播放| 成人在线免费av| 欧美日韩国产一区| 午夜视频在线免费看| 成人av地址| 亚洲精品一区二区三区不| 亚洲av无码一区二区二三区| 精品高清久久| 久久久999国产| 国产一级一片免费播放| 亚洲在线成人| 国产精品嫩草影院一区二区| 国产高清不卡视频| 99久久久久久| 色乱码一区二区三在线看| 免费在线观看黄色网| 亚洲永久免费av| www.中文字幕在线| 日韩专区视频| 亚洲精品一区二区三区四区高清| 日本黄色网址大全| 五月久久久综合一区二区小说| 欧美日韩国产91| 久久久免费高清视频| 免费看日韩精品| 成人免费视频网站入口| 国产在线观看免费| 一区二区三区日韩| 欧美精品aaaa| 9l视频自拍九色9l视频成人| 国产一区二区av| 波多野结衣亚洲色图| 香蕉亚洲视频| 成人欧美一区二区三区视频| 黄视频在线观看免费| 亚洲精品国产视频| 国内自拍视频一区| 成人av激情人伦小说| 色青青草原桃花久久综合| 国产精品.www| 久久国产免费看| 精品国产乱码久久久久久丨区2区| 成年人视频网站在线| 亚洲国产精品影院| 天堂av在线8| 伊人春色精品| 久久久久久久电影一区| 中国女人一级一次看片| 91麻豆国产在线观看| 肉大捧一出免费观看网站在线播放 | 一本大道熟女人妻中文字幕在线 | 国产亚洲精品熟女国产成人| 亚洲一级网站| 亚洲一区二区在线播放| 成人高清免费观看mv| 亚洲va天堂va国产va久| 午夜视频在线观| 欧美色蜜桃97| 欧美综合一区第一页| 国产成人三级在线观看视频| 日韩毛片在线免费观看| 欧美精品aaaa| 国产精品一区2区3区| 性欧美亚洲xxxx乳在线观看| 国产黄色片网站| 亚洲青青青在线视频| 性刺激的欧美三级视频| 国产精品亚洲二区| 日本欧美黄网站| 天堂成人在线视频| 亚洲国产一区二区三区青草影视| 亚洲欧美日韩网站| 久久久久久久久久久9不雅视频| 国产精品久久久久久中文字 | 久久亚洲春色中文字幕| 亚洲系列在线观看| 国产精品亲子乱子伦xxxx裸| 尤蜜粉嫩av国产一区二区三区| 国产欧美日韩精品一区二区三区| 日韩av快播网址| 免费在线观看一级毛片| 一本一本久久a久久精品综合麻豆 一本一道波多野结衣一区二区 | xxxcom在线观看| 精品精品欲导航| 黄色小视频在线免费看| 99久久久久久| 成人在线观看黄| 精品国产精品久久一区免费式| 国产精品大陆在线观看| www.中文字幕久久久| 欧美三片在线视频观看| 日韩精品一区二区三区在线视频| 久久国产精品72免费观看| 亚洲国产精品影视| 中文字幕av一区二区三区四区| 欧美激情国内偷拍| 神马午夜在线观看| 日本二三区不卡| 男人晚上看的视频| 国产xxx精品视频大全| 青青青在线视频播放| 欧美影院天天5g天天爽| 国产精品草莓在线免费观看 | 精品国产av鲁一鲁一区| 亚洲国产精品自拍| 亚洲成人网在线播放| 免费黄网站欧美| 久久人妻无码一区二区| 色婷婷av一区二区三区丝袜美腿| 国产99久久久欧美黑人| 欧美精品电影| 亚洲精品一区二区三区蜜桃下载 | 51午夜精品国产| 国产一级特黄a高潮片| 2022国产精品视频| 欧美一级xxxx| aa亚洲婷婷| 亚洲一卡二卡三卡四卡无卡网站在线看 | 天天影视综合| 国产免费一区二区三区| 日本精品网站| 久久久久久久国产精品视频| 国产网站在线播放| 日韩精品一区二区三区swag| 日韩毛片一区二区三区| 亚洲三级在线播放| 四虎永久免费影院| 国产呦精品一区二区三区网站| 极品粉嫩国产18尤物| 水蜜桃久久夜色精品一区| 国产日韩欧美综合精品| 中文成人在线| 热99在线视频| 欧美bbbxxxxx| 在线播放亚洲激情| 污视频在线免费观看| 91麻豆精品国产91久久久久久久久| 日韩在线视频免费播放| 亚洲精品成a人| 91成人精品一区二区| 成人app下载| 亚洲网中文字幕| 久久国产主播| cao在线观看| 午夜激情一区| 91免费视频黄| 日韩av专区| 欧美日韩在线高清| 国内自拍欧美| 99视频日韩| 国产精品3区| 国产日韩在线观看av| 欧美性xxx| 91高清免费在线观看| 男人天堂亚洲天堂| 久久影院在线观看| 日本不卡在线| 中文字幕亚洲一区二区三区五十路| 色窝窝无码一区二区三区| 9191久久久久久久久久久| wwwwww在线观看| 日韩欧美精品网站| 中日韩黄色大片| 亚洲国产aⅴ成人精品无吗| 欧美成人片在线| 亚洲一区二区中文在线| 美国黄色片视频| 国产欧美一区二区在线| 三级黄色片网站| 成人免费视频视频| 中文字幕亚洲日本| 国产真实乱对白精彩久久| www.se五月| 另类小说视频一区二区| 青青青国产在线视频| 午夜一级久久| 国产超级av在线| 国产日韩一区| 国产免费毛卡片| 久久久久久久波多野高潮日日| 久久无码高潮喷水| 久久久蜜桃一区二区人| 日韩一级免费在线观看| 视频一区在线视频| 久草资源站在线观看| 久久在线精品| 日本久久精品一区二区| 蜜乳av一区二区三区| 午夜不卡福利视频| 国产成人免费网站| 漂亮人妻被黑人久久精品| av亚洲产国偷v产偷v自拍| 国产呦小j女精品视频| 国产无一区二区| a级黄色免费视频| 中文字幕亚洲在| 青娱乐国产在线| 精品久久久久久久久久久| 亚洲综合久久网| 欧美日韩中文精品| 99国产精品久久久久99打野战| 日韩一区二区中文字幕| 深夜福利视频网站| 亚洲色图国产精品| 欧美成人hd| 久久久免费高清电视剧观看| 亚洲精品中文字幕| 国产日韩欧美综合| 成人知道污网站| 久久精品一二三区| 久久中文字幕av| 国产手机免费视频| 日日欢夜夜爽一区| 青娱乐精品在线| 99久久国产综合精品麻豆| 亚洲综合欧美综合| 亚洲综合男人的天堂| 无码日韩精品一区二区| 91精品黄色片免费大全| 网站黄在线观看| 按摩亚洲人久久| 蜜桃麻豆av在线| 成人h视频在线观看播放| 成人偷拍自拍| 亚洲日本无吗高清不卡| 亚洲福利精品| 亚洲欧美国产中文| 99综合电影在线视频| 成人一级片免费看| 亚洲成人在线免费| 国产精品国产三级国产普通话对白| 精品va天堂亚洲国产| 日本免费在线观看| 欧美一级电影久久| 日韩精品成人在线观看| 水蜜桃一区二区三区| 亚洲国产综合在线看不卡| 色www免费视频| 久久久久久黄色| xxxx 国产| 666欧美在线视频| 成人欧美亚洲| 97在线视频免费看| 久久wwww| 中文字幕日韩一区二区三区不卡| 翔田千里一区二区| 88av在线播放| 一区二区三区四区视频精品免费 | 一本一本大道香蕉久在线精品 | 国产一区二区三区在线观看免费 | 久久93精品国产91久久综合| 天堂а√在线中文在线| 久久精品国产精品亚洲综合| 国产精品亚洲无码| 天天影视网天天综合色在线播放| 国产成人精品av在线观| 日韩视频欧美视频| 成人精品一区二区三区电影| 欧美日韩日本网| 国产精品呻吟| 国产麻豆xxxvideo实拍| 亚洲一二三级电影| www香蕉视频| 久热精品视频在线| 国产成人久久精品一区二区三区| 亚洲国产一区二区精品视频| 日日骚欧美日韩| 美女被到爽高潮视频| 日韩欧美精品中文字幕| 头脑特工队2在线播放| 992tv成人免费视频| 另类ts人妖一区二区三区| 日韩av高清在线看片| 成人一区在线观看| 黄色小说在线观看视频| 亚洲第一色中文字幕| av福利在线导航| 国产综合动作在线观看| 亚洲三级观看| 精品久久久久久中文字幕人妻最新| 精品成人在线视频| 深夜福利在线视频| 国产不卡av在线免费观看| 亚洲日产av中文字幕| 无人在线观看的免费高清视频| 国产精品无遮挡| 国产精品久久久久久免费播放| 久久精品小视频| 中文字幕久久精品一区二区| 免费视频爱爱太爽了| 99久久国产综合精品色伊| 国产亚洲欧美日韩高清| 中文字幕精品久久久久| 偷拍自拍亚洲| 日本福利视频在线观看| www.99精品| 成人a v视频| 最近2019年好看中文字幕视频| 91国产精品| 91动漫在线看| 久久久精品人体av艺术| 亚洲一区二区影视| 欧美大片欧美激情性色a∨久久| 成人在线超碰| 国产天堂在线播放| 亚洲伦理在线精品| 网站黄在线观看| 国产日韩在线视频| 精久久久久久| 久久久免费看片| 日韩欧美国产午夜精品| 中文在线а√天堂| 欧美 日韩 国产 在线观看 | 99视频国产精品免费观看| 午夜在线视频一区二区区别| 免费一级特黄3大片视频| 日韩一本二本av| 国产精品迅雷| 天堂av在线中文| 久久色视频免费观看| 91在线你懂的| 18久久久久久| 亚洲成人99| 大又大又粗又硬又爽少妇毛片 | 精品视频黄色| 久久久国产精品久久久| 欧美自拍偷拍一区| 成人免费一区二区三区牛牛| 日韩一区国产在线观看| 成人免费视频app|