1. 程式人生 > >dubbo 學習(5) dubbo多協議和多註冊中心

dubbo 學習(5) dubbo多協議和多註冊中心

一、配置dubbo多協議模式

1、預設協議

 Dubbo預設協議採用單一長連線和NIO非同步通訊,適合於小資料量大併發的服務呼叫,以及服務消費者機器數遠大於服務提供者機器數的情況。Dubbo預設協議不適合傳送大資料量的服務,比如傳檔案,傳視訊等,除非請求量很低。

<dubbo:protocolname="dubbo"port="20880"/>

Set default protocol:

<dubbo:providerprotocol="dubbo"/>

Set service protocol:

<dubbo:serviceprotocol
="dubbo"/>

Multi port:

<dubbo:protocolid="dubbo1"name="dubbo"port="20880"/> <dubbo:protocolid="dubbo2"name="dubbo"port="20881"/>

Dubbo protocol options:

<dubbo:protocolname=“dubbo” port=“9090” server=“netty” client=“netty” codec=“dubbo” serialization=“hessian2” charset=“UTF-8” threadpool=“fixed” threads=“100” queues=“0” iothreads=“9” buffer=“8192” accepts=“1000” payload=“8388608” />

Dubbo協議預設每服務每提供者每消費者使用單一長連線,如果資料量較大,可以使用多個連線。

<dubbo:protocolname="dubbo"connections="2"/>
  • <dubbo:service connections=”0”>或<dubbo:reference connections=”0”>表示該服務使用JVM共享長連線。(預設)
  • <dubbo:service connections=”1”>或<dubbo:reference connections=”1”>表示該服務使用獨立長連線。
  • <dubbo:service connections=”2”>或<dubbo:reference connections=”2”>表示該服務使用獨立兩條長連線。
為防止被大量連線撐掛,可在服務提供方限制大接收連線數,以實現服務提供方自我保護。
<dubbo:protocolname="dubbo"accepts="1000"/>

預設協議,使用基於mina1.1.7+hessian3.2.1的tbremoting互動。

  • 連線個數:單連線
  • 連線方式:長連線
  • 傳輸協議:TCP
  • 傳輸方式:NIO非同步傳輸
  • 序列化:Hessian二進位制序列化
  • 適用範圍:傳入傳出引數資料包較小(建議小於100K),消費者比提供者個數多,單一消費者無法壓滿提供者,儘量不要用dubbo協議傳輸大檔案或超大字串
  • 適用場景:常規遠端服務方法呼叫

為什麼要消費者比提供者個數多:
因dubbo協議採用單一長連線,
假設網路為千兆網絡卡(1024Mbit=128MByte),
根據測試經驗資料每條連線最多隻能壓滿7MByte(不同的環境可能不一樣,供參考),
理論上1個服務提供者需要20個服務消費者才能壓滿網絡卡。

為什麼不能傳大包:
因dubbo協議採用單一長連線,
如果每次請求的資料包大小為500KByte,假設網路為千兆網絡卡(1024Mbit=128MByte),每條連線最大7MByte(不同的環境可能不一樣,供參考),
單個服務提供者的TPS(每秒處理事務數)最大為:128MByte / 500KByte = 262。
單個消費者呼叫單個服務提供者的TPS(每秒處理事務數)最大為:7MByte / 500KByte = 14。
如果能接受,可以考慮使用,否則網路將成為瓶頸。

為什麼採用非同步單一長連線:
因為服務的現狀大都是服務提供者少,通常只有幾臺機器,
而服務的消費者多,可能整個網站都在訪問該服務,
比如Morgan的提供者只有6臺提供者,卻有上百臺消費者,每天有1.5億次呼叫,
如果採用常規的hessian服務,服務提供者很容易就被壓跨,
通過單一連線,保證單一消費者不會壓死提供者,
長連線,減少連線握手驗證等,
並使用非同步IO,複用執行緒池,防止C10K問題。

(1) 約束:

  • 引數及返回值需實現Serializable介面
  • 引數及返回值不能自定義實現List, Map, Number, Date, Calendar等介面,只能用JDK自帶的實現,因為hessian會做特殊處理,自定義實現類中的屬性值都會丟失。()
  • Hessian序列化,只傳成員屬性值和值的型別,不傳方法或靜態變數,相容情況:(由吳亞軍提供)
    資料通訊 情況 結果
    A->B 類A多一種 屬性(或者說類B少一種 屬性) 不拋異常,A多的那 個屬性的值,B沒有, 其他正常
    A->B 列舉A多一種 列舉(或者說B少一種 列舉),A使用多 出來的列舉進行傳輸 拋異常
    A->B 列舉A多一種 列舉(或者說B少一種 列舉),A不使用 多出來的列舉進行傳輸 不拋異常,B正常接 收資料
    A->B A和B的屬性 名相同,但型別不相同 拋異常
    A->B serialId 不相同 正常傳輸

    總結:會拋異常的情況:枚 舉值一邊多一種,一邊少一種,正好使用了差別的那種,或者屬性名相同,型別不同

介面增加方法,對客戶端無影響,如果該方法不是客戶端需要的,客戶端不需要重新部署;
輸入引數和結果集中增加屬性,對客戶端無影響,如果客戶端並不需要新屬性,不用重新
部署;
輸入引數和結果集屬性名變化,對客戶端序列化無影響,但是如果客戶端不重新部署,不管輸入還是輸出,屬性名變化的屬性值是獲取不到的。
總結:伺服器端和客戶端對領域物件並不需要完全一致,而是按照最大匹配原則。

(2) 配置:
dubbo.properties:

dubbo.service.protocol=dubbo

2、 rmi協議

RMI協議採用JDK標準的java.rmi.*實現,採用阻塞式短連線和JDK標準序列化方式。
  • 如果服務介面繼承了java.rmi.Remote介面,可以和原生RMI互操作,即:
    • 提供者用Dubbo的RMI協議暴露服務,消費者直接用標準RMI介面呼叫,
    • 或者提供方用標準RMI暴露服務,消費方用Dubbo的RMI協議呼叫。
  • 如果服務介面沒有繼承java.rmi.Remote介面,
    • 預設Dubbo將自動生成一個com.xxx.XxxService$Remote的介面,並繼承java.rmi.Remote介面,並以此介面暴露服務,
    • 但如果設定了<dubbo:protocol name="rmi" codec="spring" />,將不生成$Remote介面,而使用Spring的RmiInvocationHandler介面暴露服務,和Spring相容。

Define rmi protocol:

<dubbo:protocolname="rmi"port="1099"/>

Set default protocol:

<dubbo:providerprotocol="rmi"/>

Set service protocol:

<dubbo:serviceprotocol="rmi"/>

Multi port:

<dubbo:protocolid="rmi1"name="rmi"port="1099"/> <dubbo:protocolid="rmi2"name="rmi"port="2099"/> <dubbo:serviceprotocol="rmi1"/>

Spring compatible:

<dubbo:protocolname="rmi"codec="spring"/>

Java標準的遠端呼叫協議。

  • 連線個數:多連線
  • 連線方式:短連線
  • 傳輸協議:TCP
  • 傳輸方式:同步傳輸
  • 序列化:Java標準二進位制序列化
  • 適用範圍:傳入傳出引數資料包大小混合,消費者與提供者個數差不多,可傳檔案。
  • 適用場景:常規遠端服務方法呼叫,與原生RMI服務互操作

(1) 約束:

  • 引數及返回值需實現Serializable介面
  • dubbo配置中的超時時間對rmi無效,需使用java啟動引數設定:-Dsun.rmi.transport.tcp.responseTimeout=3000,參見下面的RMI配置。

(2) 配置:
dubbo.properties:

dubbo.service.protocol=rmi

(3) RMI配置:

java -Dsun.rmi.transport.tcp.responseTimeout=3000

3、 hessian協議

Hessian協議用於整合Hessian的服務,Hessian底層採用Http通訊,採用Servlet暴露服務,Dubbo預設內嵌Jetty作為伺服器實現。

Hessian是Caucho開源的一個RPC框架:http://hessian.caucho.com,其通訊效率高於WebService和Java自帶的序列化。

依賴:

<dependency> <groupId>com.caucho</groupId> <artifactId>hessian</artifactId> <version>4.0.7</version> </dependency>

可以和原生Hessian服務互操作,即:

  • 提供者用Dubbo的Hessian協議暴露服務,消費者直接用標準Hessian介面呼叫,
  • 或者提供方用標準Hessian暴露服務,消費方用Dubbo的Hessian協議呼叫。

基於Hessian的遠端呼叫協議。

  • 連線個數:多連線
  • 連線方式:短連線
  • 傳輸協議:HTTP
  • 傳輸方式:同步傳輸
  • 序列化:Hessian二進位制序列化
  • 適用範圍:傳入傳出引數資料包較大,提供者比消費者個數多,提供者壓力較大,可傳檔案。
  • 適用場景:頁面傳輸,檔案傳輸,或與原生hessian服務互操作

(1) 約束:

  • 引數及返回值需實現Serializable介面
  • 引數及返回值不能自定義實現List, Map, Number, Date, Calendar等介面,只能用JDK自帶的實現,因為hessian會做特殊處理,自定義實現類中的屬性值都會丟失。

(2) 配置:
Define hessian protocol:

<dubbo:protocolname="hessian"port="8080"server="jetty"/>

Set default protocol:

<dubbo:providerprotocol="hessian"/>

Set service protocol:

<dubbo:serviceprotocol="hessian"/>

Multi port:

<dubbo:protocolid="hessian1"name="hessian"port="8080"/> <dubbo:protocolid="hessian2"name="hessian"port="8081"/>

Directly provider:

<dubbo:referenceid="helloService"interface="HelloWorld"url="hessian://10.20.153.10:8080/helloWorld"/>

h4. Jetty Server: (default)

<dubbo:protocol... server="jetty"/>

h4. Servlet Bridge Server: (recommend)

<dubbo:protocol... server="servlet"/>

web.xml:

<servlet> <servlet-name>dubbo</servlet-name> <servlet-class>com.alibaba.dubbo.remoting.http.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dubbo</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>

注意,如果使用servlet派發請求:

  • 協議的埠<dubbo:protocol port="8080" />必須與servlet容器的埠相同,
  • 協議的上下文路徑<dubbo:protocol contextpath="foo" />必須與servlet應用的上下文路徑相同。
4、http協議

   此協議採用spring 的HttpInvoker的功能實現,

  連線個數:多個

  連線方式:長連線

  連線協議:http

  傳輸方式:同步傳輸

  序列化:表單序列化

  適用範圍:傳入傳出引數資料包大小混合,提供者比消費者個數多,可用瀏覽器檢視,可用表單或URL傳入引數,暫不支援傳檔案。

  適用場景:需同時給應用程式和瀏覽器JS使用的服務。

配置:

<dubbo:protocol name="http" port="8080" />

5、thrift協議
當前 dubbo 支援的 thrift 協議是對 thrift 原生協議的擴充套件,在原生協議的基礎上添加了一些額外的頭資訊,比如service name,magic number等。使用dubbo thrift協議同樣需要使用thrift的idl compiler編譯生成相應的java程式碼,後續版本中會在這方面做一些增強

新增依賴

<dependency>
    <groupId>org.apache.thrift</groupId>
    <artifactId>libthrift</artifactId>
    <version>0.8.0</version>
</dependency>

所有服務共用一個埠:(與原生Thrift不相容)

<dubbo:protocol name="thrift" port="3030" />

Thrift不支援資料型別:

  • null值 (不能在協議中傳遞null值)

 所有配置資訊如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd        http://code.alibabatech.com/schema/dubbo        http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
 
    <!-- 提供方應用資訊,用於計算依賴關係 -->
    <dubbo:application name="hello-world-app"  />
 
    <!-- 使用multicast廣播註冊中心暴露服務地址 -->
    <dubbo:registry address="zookeeper://127.0.0.1:2181" />   
 
    <!-- 用dubbo協議在20880埠暴露服務 -->
    <dubbo:protocol name="dubbo" port="20880" />
     <dubbo:protocol name="rmi" port="1099" />
   <dubbo:protocol name="http" port="1199" />
    <dubbo:protocol name="hessian" port="8080" />
 <!-- 宣告需要暴露的服務介面 ,若選擇hessian協議,需要加入hessian包-->  
      <dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService"   protocol="hessian"/>   
   
    <!-- 和本地bean一樣實現服務 -->  
    <bean id="demoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl" />  
    
 <!-- 掃描註解包路徑,多個包用逗號分隔,不填pacakge表示掃描當前ApplicationContext中所有的類 -->
<dubbo:annotation package="com.alibaba.dubbo.annotation.service" />
</beans>

同服務使用多協議

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsd">
 
    <dubbo:application name="world"  />
    <dubbo:registry id="registry" address="10.20.141.150:9090" username="admin" password="hello1234" />
 
    <!-- 多協議配置 -->
    <dubbo:protocol name="dubbo" port="20880" />
    <dubbo:protocol name="hessian" port="8080" />
 
    <!-- 使用多個協議暴露服務 -->
    <dubbo:service id="helloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" protocol="dubbo,hessian" />
 
</beans>

二、多註冊中心

同時向2個註冊中心,註冊服務,這樣,2個註冊中心都擁有此服務

同樣,不同的服務可以註冊到不同的註冊中心,比如:CRM有些服務是專門為國際站設計的,有些服務是專門為中文站設計的(官方文件舉得例子)。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd        http://code.alibabatech.com/schema/dubbo        http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
 
    <!-- 提供方應用資訊,用於計算依賴關係 -->
    <dubbo:application name="hello-world-app"  />
 
    <!-- 使用multicast廣播註冊中心暴露服務地址 -->
    <dubbo:registry  id="localhost"  address="zookeeper://127.0.0.1:2181" />   
   <dubbo:registry id="localcomputer"  address="192.168.0.12:9010" default="false" />
    <!-- 用dubbo協議在20880埠暴露服務 -->
    <dubbo:protocol name="dubbo" port="20880" />
     <dubbo:protocol name="rmi" port="1099" />
  <!-- 宣告需要暴露的服務介面 -->  
    <dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService"   protocol="rmi" registry="localhost,localcomputer" />  
   
    <!-- 和本地bean一樣實現服務 -->  
    <bean id="demoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl" />  
    
 <!-- 掃描註解包路徑,多個包用逗號分隔,不填pacakge表示掃描當前ApplicationContext中所有的類 -->
<dubbo:annotation package="com.alibaba.dubbo.annotation.service"  />
</beans>