dubbo 學習(5) dubbo多協議和多註冊中心
一、配置dubbo多協議模式
1、預設協議
Dubbo預設協議採用單一長連線和NIO非同步通訊,適合於小資料量大併發的服務呼叫,以及服務消費者機器數遠大於服務提供者機器數的情況。Dubbo預設協議不適合傳送大資料量的服務,比如傳檔案,傳視訊等,除非請求量很低。
<
dubbo:protocol
name
=
"dubbo"
port
=
"20880"
/>
Set default protocol:
< dubbo:provider protocol = "dubbo" />
|
Set service protocol:
< dubbo:service protocol = "dubbo" />
|
Multi port:
< dubbo:protocol id = "dubbo1" name = "dubbo" port = "20880" />
< dubbo:protocol id = "dubbo2" name = "dubbo" port = "20881" />
|
Dubbo protocol options:
<
dubbo:protocol
name=“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:protocol name = "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:protocol name = "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:protocol name = "rmi" port = "1099" />
|
Set default protocol:
< dubbo:provider protocol = "rmi" />
|
Set service protocol:
< dubbo:service protocol = "rmi" />
|
Multi port:
< dubbo:protocol id = "rmi1" name = "rmi" port = "1099" />
< dubbo:protocol id = "rmi2" name = "rmi" port = "2099" />
< dubbo:service protocol = "rmi1" />
|
Spring compatible:
< dubbo:protocol name = "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:protocol name = "hessian" port = "8080" server = "jetty" />
|
Set default protocol:
< dubbo:provider protocol = "hessian" />
|
Set service protocol:
< dubbo:service protocol = "hessian" />
|
Multi port:
< dubbo:protocol id = "hessian1" name = "hessian" port = "8080" />
< dubbo:protocol id = "hessian2" name = "hessian" port = "8081" />
|
Directly provider:
< dubbo:reference id = "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應用的上下文路徑相同。
此協議採用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>