Dubbo API 筆記——Dubbo協議&最佳實踐

Dubbo協議

dubbo://

Dubbo缺省協議採用單一長連接和NIO異步通訊,適合於小數據量大併發的服務調用,以及服務消費者機器遠大於服務提供者機器數的情況

反之,Dubbo 缺省協議不適合傳送大數據量的服務,比如傳文件,傳視頻等,除非請求量很低

<img du011>

特性

缺省協議,使用基於 mina 1.1.7 和 hessian 3.2.1 的 tbremoting 交互

  • 連接個數:單連接
  • 連接方式:長連接
  • 傳輸協議:TCP
  • 傳輸方式:NIO 異步傳輸
  • 序列化:Hessian 二進制序列化
  • 適用範圍:傳入傳出參數數據包較小(建議小於100K),消費者比提供者個數多,單一消費者無法壓滿提供者,儘量不要用 dubbo 協議傳輸大文件或超大字符串
  • 適用場景:常規遠程服務方法調用

約束

  • 參數及返回值需實現 Serializable 接口
  • 參數及返回值不能自定義實現 List, Map, Number, Date, Calendar 等接口,只能用 JDK 自帶的實現,因爲 hessian 會做特殊處理,自定義實現類中的屬性值都會丟失
  • Hessian 序列化,只傳成員屬性值和值的類型,不傳方法或靜態變量,兼容情況
數據通訊 情況
A->B 類A多一種屬性(或者說類B少一種屬性)
A->B 枚舉A多一種枚舉(或者說B少一種枚舉),A使用多出來的枚舉進行傳輸
A->B 枚舉A多一種枚舉(或者說B少一種枚舉),A不使用多出來的枚舉進行傳輸
A->B A和B的屬性名相同,但類型不相同
A->B serialId不相同

配置

配置協議

<dubbo:protocol name="dubbo" port="20880" />

配置協議選項

<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:protocol name="dubbo" accepts="1000" />

rmi://

RMI 協議採用 JDK 標準的 java.rmi.* 實現,採用阻塞式短連接和 JDK 標準序列化方式

特性

  • 連接個數:多連接
  • 連接方式:短連接
  • 傳輸協議:TCP
  • 傳輸方式:同步傳輸
  • 序列化:Java 標準二進制序列化
  • 適用範圍:傳入傳出參數數據包大小混合,消費者與提供者個數差不多,可傳文件
  • 適用場景:常規遠程服務方法調用,與原生RMI服務互操作

約束

  • 參數及返回值需實現 Serializable 接口 dubbo 配置中的超時時間對 RMI 無效,需使用 java 啓動參數設置:

    Dsun.rmi.transport.tcp.responseTimeout=3000 
    

配置

定義RMI協議

<dubbo:protocol name="rmi" port="1099" />

多端口

<dubbo:protocol id="rmi1" name="rmi" port="1099" /> 
<dubbo:protocol id="rmi2" name="rmi" port="2099" />

<dubbo:service  protocol="rmi1" />

hessian://

Hessian 協議用於集成 Hessian 的服務,Hessian 底層採用 Http 通訊,採用 Servlet 暴露服務,Dubbo 缺省內嵌 Jetty 作爲服務器實現

特性

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

依賴

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

約束

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

配置

定義 hessian 協議

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

多端口

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

直連

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

zookeeper註冊中心

Zookeeper 是 Apacahe Hadoop 的子項目,是一個樹型的目錄服務,支持變更推送,適合作爲 Dubbo 服務的註冊中心,工業強度較高,可用於生產環境,並推薦使用

<img du_012>

流程說明

  • 服務提供者啓動時: 向 /dubbo/com.foo.BarService/providers 目錄下寫入自己的 URL 地址
  • 服務消費者啓動時: 訂閱 /dubbo/com.foo.BarService/providers 目錄下的提供者 URL 地址。並向 /dubbo/com.foo.BarService/consumers 目錄下寫入自己的 URL 地址
  • 監控中心啓動時: 訂閱 /dubbo/com.foo.BarService 目錄下的所有提供者和消費者 URL 地址

支持以下功能

  • 當提供者出現斷電等異常停機時,註冊中心能自動刪除提供者信息
  • 當註冊中心重啓時,能自動恢復註冊數據,以及訂閱請求
  • 當會話過期時,能自動恢復註冊數據,以及訂閱請求
  • 當設置 <dubbo:registry check=”false” /> 時,記錄失敗註冊和訂閱請求,後臺定時重試
  • 可通過 <dubbo:registry username=”admin” password=”1234” /> 設置 zookeeper 登錄信息
  • 可通過 <dubbo:registry group=”dubbo” /> 設置 zookeeper 的根節點,不設置將使用無根樹
  • 支持 * 號通配符 <dubbo:reference group=”” version=”” />,可訂閱服務的所有分組和所有版本的提供者

使用

在 provider 和 consumer 中增加 zookeeper 客戶端 jar 包依賴

<dependency>                
    <groupId>org.apache.zookeeper</groupId>         
    <artifactId>zookeeper</artifactId>      
    <version>3.3.3</version> 
</dependency>

使用zkclient客戶端實現

缺省配置

<dubbo:registry ... client="zkclient" />

需依賴

<dependency>                
    <groupId>com.github.sgroschupf</groupId>                
    <artifactId>zkclient</artifactId>               
    <version>0.1</version> 
</dependency>

Zookeeper 單機配置

<dubbo:registry protocol="zookeeper" address="10.20.153.10:2181" />

Zookeeper 集羣配置

<dubbo:registry protocol="zookeeper" address="10.20.153.10:2181,10.20.153.11:2181,10.2 0.153.12:2181" />

同一 Zookeeper,分成多組註冊中心

<dubbo:registry id="chinaRegistry" protocol="zookeeper" address="10.20.153.10:2181" group="china" /> 
<dubbo:registry id="intlRegistry" protocol="zookeeper" address="10.20.153.10:2181" group="intl" />

服務化最佳實踐

分包

建議將服務接口,服務模型,服務異常等均放在 API 包中,因爲服務模型及異常也是 API 的一部分,同時,這樣做也符合分包原則:重用發佈等價原則(REP),共同重用原則(CRP)

如果需要,也可以考慮在 API 包中放置一份 spring 的引用配置,這樣使用方,只需在 spring 加載過程中引用此配置即可,配置建議放在模塊的包目錄下,以免衝突, 如: com/alibaba/china/xxx/dubbo-reference.xml

粒度

服務接口儘可能大粒度,每個服務方法應代表一個功能,而不是某功能的一個步驟,否則將面臨分佈式事務問題,Dubbo 暫未提供分佈式事務支持

服務接口建議以業務場景爲單位劃分,並對相近業務做抽象,防止接口數量爆炸

不建議使用過於抽象的通用接口,如: Map query(Map) ,這樣的接口沒有明確語義,會給後 期維護帶來不便

版本

每個接口都應定義版本號,爲後續不兼容升級提供可能,如:<dubbo:service interface=”com.xxx.XxxService” version=”1.0” />

建議使用兩位版本號,因爲第三位版本號通常表示兼容升級,只有不兼容時才需要變更服務版本

當不兼容時,先升級一半提供者爲新版本,再將消費者全部升爲新版本,然後將剩下的一半提供者升爲新版本

兼容性

服務接口增加方法,或服務模型增加字段,可向後兼容,刪除方法或刪除字段,將不兼容,枚舉類型新增字段也不兼容,需通過變更版本號升級

枚舉值

如果是完備集,可以用 Enum,比如: ENABLE, DISABLE

如果是業務種類,以後明顯會有類型增加,不建議用 Enum,可以用 String 代替

如果是在返回值中用了 Enum,並新增了 Enum 值,建議先升級服務消費方,這樣服務提供方不會返回新值

如果是在傳入參數中用了 Enum,並新增了 Enum 值,建議先升級服務提供方,這樣服務消費方不會傳入新值

序列化

服務參數及返回值建議使用 POJO 對象,即通過 setter, getter 方法表示屬性的對象

服務參數及返回值不建議使用接口,因爲數據模型抽象的意義不大,並且序列化需要接口實現類的元信息,並不能起到隱藏實現的意圖

服務參數及返回值都必需是 byValue 的,而不能是 byReference 的,消費方和提供方的參數或返回值引用並不是同一個,只是值相同,Dubbo 不支持引用遠程對象

異常

建議使用異常彙報錯誤,而不是返回錯誤碼,異常信息能攜帶更多信息,以及語義更友好

如果擔心性能問題,在必要時,可以通過 override 掉異常類的 fillInStackTrace() 方法爲空方法,使其不拷貝棧信息

查詢方法不建議拋出 checked 異常,否則調用方在查詢時將過多的 try…catch,並且不能進行有效處理

服務提供方不應將 DAO 或 SQL 等異常拋給消費方,應在服務實現中對消費方不關心的異常進行包裝,否則可能出現消費方無法反序列化相應異常

調用

不要只是因爲是 Dubbo 調用,而把調用 try…catch 起來。 try…catch 應該加上合適的 回滾邊界上

對於輸入參數的校驗邏輯在 Provider 端要有。如有性能上的考慮,服務實現者可以考慮在 API 包上加上服務 Stub 類來完成檢驗

推薦用法

在Provider上儘量多配置Consumer端屬性

原因

  • 作服務的提供者,比服務使用方更清楚服務性能參數,如調用的超時時間,合理的重試次數,等等
  • 在 Provider 配置後,Consumer 不配置則會使用 Provider 的配置值,即 Provider 配置可以作爲 Consumer 的缺省值。否則,Consumer 會使用 Consumer 端的全局設置,這對於 Provider 不可控的,並且往往是不合理的

示例

<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="hel loService" timeout="300" retry="2" loadbalance="random" actives="0" />

<dubbo:service interface="com.alibaba.hello.api.WorldService" version="1.0.0" ref="helloService" timeout="300" retry="2" loadbalance="random" actives="0" >
    <dubbo:method name="findAllPerson" timeout="10000" retries="9" loadbalance="leastactive" actives="5" /> 
<dubbo:service/>

可在Provider上配置的Consumer屬性有

  • timeout 方法調用超時
  • retries 失敗重試次數,缺省是 2
  • loadbalance 負載均衡算法,缺省是隨機 random。還可以有輪詢 roundrobin、最不活躍優先 leastactive
  • actives 消費者端,最大併發調用限制,即當 Consumer 對一個服務的併發調用到上限後,新調用會 Wait 直到超時,在方法上配置 dubbo:method 則併發限制針對方法,在接口上配置 dubbo:service ,則併發限制針對服務

Provider 上配置合理的 Provider 端屬性

<dubbo:protocol threads="200" />    
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" executes="200">                    
    <dubbo:method name="findAllPerson" executes="50" /> 
</dubbo:service>

Provider 上可以配置的 Provider 端屬性有

  • threads 服務線程池大小
  • executes 一個服務提供者並行執行請求上限,即當 Provider 對一個服務的併發調用到上限後,新調用會 Wait,這個時候Consumer可能會超時。在方法上配置 dubbo:method 則併發限制針對方法,在接口上配置 dubbo:service,則併發限制針對服務

配置Dubbo緩存文件

提供者列表緩存文件

<dubbo:registry file="${user.home}/output/dubbo.cache" />

這個文件會緩存註冊中心的列表和服務提供者列表。有了這項配置後,當應用重啓過程中,Dubbo 註冊中心不可用時則應用會從這個緩存文件讀取服務提供者列表的信息,進一步保證應用可靠性

發佈了84 篇原創文章 · 獲贊 135 · 訪問量 41萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章