Dubbo 缺省會在啓動時檢查依賴的服務是否可用,不可用時會拋出異常,阻止 Spring 初始化完成,以便上線時,能及早發現問題,默認 check="true"
。另外,若是你的 Spring 容器是懶加載的,或者經過 API 編程延遲引用服務,請關閉 check,不然服務臨時不可用時,會拋出異常,拿到 null 引用,若是 check="false"
,老是會返回引用,當服務恢復時,能自動連上。html
Failover Cluster 失敗自動切換,當出現失敗,重試其它服務器 。一般用於讀操做,但重試會帶來更長延遲。可經過 retries="2"
來設置重試次數(不含第一次)。java
Failfast Cluster 快速失敗,只發起一次調用,失敗當即報錯。用於非冪等性的寫操做,好比新增記錄。node
Failsafe Cluster失敗安全,出現異常時,直接忽略。一般用於寫入審計日誌等操做。算法
Failback Cluster失敗自動恢復,後臺記錄失敗請求,定時重發。一般用於消息通知操做。spring
Forking Cluster並行調用多個服務器,只要一個成功即返回。一般用於實時性要求較高的讀操做,但須要浪費更多服務資源。可經過 forks="2"
來設置最大並行數。apache
Broadcast Cluster廣播調用全部提供者,逐個調用,任意一臺報錯則報錯 2。一般用於通知全部提供者更新緩存或日誌等本地資源信息。編程
在集羣負載均衡時,Dubbo 提供了多種均衡策略,缺省爲random隨機調用。api
Random LoadBalance緩存
RoundRobin LoadBalancetomcat
LeastActive LoadBalance
ConsistentHash LoadBalance
<dubbo:parameter key="hash.arguments" value="0,1" />
<dubbo:parameter key="hash.nodes" value="320" />
經過不一樣的派發策略和不一樣的線程池配置的組合來應對不一樣的場景:
<dubbo:protocol name="dubbo" dispatcher="all" threadpool="fixed" threads="100" />
Dispatcher
all
全部消息都派發到線程池,包括請求,響應,鏈接事件,斷開事件,心跳等。direct
全部消息都不派發到線程池,所有在 IO 線程上直接執行。message
只有請求響應消息派發到線程池,其它鏈接斷開事件,心跳等消息,直接在 IO 線程上執行。execution
只請求消息派發到線程池,不含響應,響應和其它鏈接斷開事件,心跳等消息,直接在 IO 線程上執行。connection
在 IO 線程上,將鏈接斷開事件放入隊列,有序逐個執行,其它消息派發到線程池。ThreadPool
fixed
固定大小線程池,啓動時創建線程,不關閉,一直持有。(缺省)cached
緩存線程池,空閒一分鐘自動刪除,須要時重建。limited
可伸縮線程池,但池中的線程數只會增加不會收縮。只增加不收縮的目的是爲了不收縮時忽然來了大流量引發的性能問題。eager
優先建立Worker
線程池。在任務數量大於corePoolSize
可是小於maximumPoolSize
時,優先建立Worker
來處理任務。當任務數量大於maximumPoolSize
時,將任務放入阻塞隊列中。阻塞隊列充滿時拋出RejectedExecutionException
。(相比於cached
:cached
在任務數量超過maximumPoolSize
時直接拋出異常而不是將任務放入阻塞隊列)在開發及測試環境下,常常須要繞過註冊中心,只測試指定服務提供者,這時候可能須要點對點直連,點對點直聯方式,將以服務接口爲單位,忽略註冊中心的提供者列表,A 接口配置點對點,不影響 B 接口從註冊中心獲取列表。
經過 XML 配置
<dubbo:reference id="xxxService" interface="com.alibaba.xxx.XxxService" url="dubbo://localhost:20890" />
經過 -D 參數指定
在 JVM 啓動參數中加入-D參數映射服務地址 ,如:
java -Dcom.alibaba.xxx.XxxService=dubbo://localhost:20890
爲方便開發測試,常常會在線下共用一個全部服務可用的註冊中心,這時,若是一個正在開發中的服務提供者註冊,可能會影響消費者不能正常運行。可讓服務提供者開發方,只訂閱服務(開發的服務可能依賴其它服務),而不註冊正在開發的服務,經過直連測試正在開發的服務。
禁用註冊配置
<dubbo:registry address="10.20.153.10:9090" register="false" />
或者
<dubbo:registry address="10.20.153.10:9090?register=false" />
若是有兩個鏡像環境,兩個註冊中心,有一個服務只在其中一個註冊中心有部署,另外一個註冊中心還沒來得及部署,而兩個註冊中心的其它應用都須要依賴此服務。這個時候,可讓服務提供者方只註冊服務到另外一註冊中心,而不從另外一註冊中心訂閱服務。
禁用訂閱配置
<dubbo:registry id="hzRegistry" address="10.20.153.10:9090" /> <dubbo:registry id="qdRegistry" address="10.20.141.150:9090" subscribe="false" />
或者
<dubbo:registry id="hzRegistry" address="10.20.153.10:9090" /> <dubbo:registry id="qdRegistry" address="10.20.141.150:9090?subscribe=false" />
Dubbo 容許配置多協議,在不一樣服務上支持不一樣協議或者同一服務上同時支持多種協議。
不一樣服務在性能上適用不一樣協議進行傳輸,好比大數據用短鏈接協議,小數據大併發用長鏈接協議。
<!-- 多協議配置 --> <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>
Dubbo 支持同一服務向多註冊中心同時註冊,或者不一樣服務分別註冊到不一樣的註冊中心上去,甚至能夠同時引用註冊在不一樣註冊中心上的同名服務。另外,註冊中心是支持自定義擴展的 。
<!-- 多註冊中心配置 --> <dubbo:registry id="hangzhouRegistry" address="10.20.141.150:9090" /> <dubbo:registry id="qingdaoRegistry" address="10.20.141.151:9010" default="false" /> <!-- 向多個註冊中心註冊 --> <dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" registry="hangzhouRegistry,qingdaoRegistry" />
當一個接口有多種實現時,能夠用 group 區分。
服務
<dubbo:service group="feedback" interface="com.xxx.IndexService" /> <dubbo:service group="member" interface="com.xxx.IndexService" />
引用
<dubbo:reference id="feedbackIndexService" group="feedback" interface="com.xxx.IndexService" /> <dubbo:reference id="memberIndexService" group="member" interface="com.xxx.IndexService" />
任意組 1:
<dubbo:reference id="barService" interface="com.foo.BarService" group="*" />
當一個接口實現,出現不兼容升級時,能夠用版本號過渡,版本號不一樣的服務相互間不引用。
能夠按照如下的步驟進行版本遷移:
version控制
按組合並返回結果,好比菜單服務,接口同樣,但有多種實現,用group區分,如今消費方需從每種group中調用一次返回結果,合併結果返回,這樣就能夠實現聚合菜單項。
搜索全部分組
<dubbo:reference interface="com.xxx.MenuService" group="*" merger="true" />
合併指定分組
<dubbo:reference interface="com.xxx.MenuService" group="aaa,bbb" merger="true" />
指定方法合併結果,其它未指定的方法,將只調用一個 Group
<dubbo:reference interface="com.xxx.MenuService" group="*"> <dubbo:method name="getMenuItems" merger="true" /> </dubbo:service>
某個方法不合並結果,其它都合併結果
<dubbo:reference interface="com.xxx.MenuService" group="*" merger="true"> <dubbo:method name="getMenuItems" merger="false" /> </dubbo:service>
指定合併策略,缺省根據返回值類型自動匹配,若是同一類型有兩個合併器時,需指定合併器的名稱 2
<dubbo:reference interface="com.xxx.MenuService" group="*"> <dubbo:method name="getMenuItems" merger="mymerge" /> </dubbo:service>
指定合併方法,將調用返回結果的指定方法進行合併,合併方法的參數類型必須是返回結果類型自己
<dubbo:reference interface="com.xxx.MenuService" group="*"> <dubbo:method name="getMenuItems" merger=".addAll" /> </dubbo:service>
結果緩存,用於加速熱門數據的訪問速度,Dubbo 提供聲明式緩存,以減小用戶加緩存的工做量。
緩存類型
lru
基於最近最少使用原則刪除多餘緩存,保持最熱的數據被緩存。threadlocal
當前線程緩存,好比一個頁面渲染,用到不少 portal,每一個 portal 都要去查用戶信息,經過線程緩存,能夠減小這種多餘訪問。jcache
與 JSR107 集成,能夠橋接各類緩存實現。配置
<dubbo:reference interface="com.foo.BarService" cache="lru" />
或:
<dubbo:reference interface="com.foo.BarService"> <dubbo:method name="findBar" cache="lru" /> </dubbo:reference>
能夠經過 RpcContext
上的 setAttachment
和 getAttachment
在服務消費方和提供方之間進行參數的隱式傳遞。
基於 NIO 的非阻塞實現並行調用,客戶端不須要啓動多線程便可完成並行調用多個遠程服務,相對多線程開銷較小。
在 consumer.xml 中配置:
<dubbo:reference id="fooService" interface="com.alibaba.foo.FooService"> <dubbo:method name="findFoo" async="true" /> </dubbo:reference>
設置是否等待消息發出:
sent="true"
等待消息發出,消息發送失敗將拋出異常。sent="false"
不等待消息發出,將消息放入 IO 隊列,即刻返回。<dubbo:method name="findFoo" async="true" sent="true" />
若是隻是想異步,徹底忽略返回值,能夠配置 return="false"
,以減小 Future 對象的建立和管理成本:
<dubbo:method name="findFoo" async="true" return="false" />
本地調用使用了 injvm 協議,是一個僞協議,它不開啓端口,不發起遠程調用,只在 JVM 內直接關聯,但執行 Dubbo 的 Filter 鏈。
配置
定義 injvm 協議
<dubbo:protocol name="injvm" />
設置默認協議
<dubbo:provider protocol="injvm" />
設置服務協議
<dubbo:service protocol="injvm" />
優先使用 injvm
<dubbo:consumer injvm="true" .../> <dubbo:provider injvm="true" .../>
或
<dubbo:reference injvm="true" .../> <dubbo:service injvm="true" .../>
注意:服務暴露與服務引用都須要聲明 injvm="true"
在調用以前、調用以後、出現異常時,會觸發 oninvoke
、onreturn
、onthrow
三個事件,能夠配置當事件發生時,通知哪一個類的哪一個方法 。
服務消費者 Callback 配置
<bean id ="demoCallback" class = "com.alibaba.dubbo.callback.implicit.NofifyImpl" /> <dubbo:reference id="demoService" interface="com.alibaba.dubbo.callback.implicit.IDemoService" version="1.0.0" group="cn" > <dubbo:method name="get" async="true" onreturn = "demoCallback.onreturn" onthrow="demoCallback.onthrow" /> </dubbo:reference>
callback
與 async
功能正交分解,async=true
表示結果是否立刻返回,onreturn
表示是否須要回調。
二者疊加存在如下幾種組合狀況 :
async=true onreturn="xxx"
async=false onreturn="xxx"
async=true
async=false
遠程服務後,客戶端一般只剩下接口,而實現全在服務器端,但提供方有些時候想在客戶端也執行部分邏輯,好比:作 ThreadLocal 緩存,提早驗證參數,調用失敗後僞造容錯數據等等,此時就須要在 API 中帶上 Stub,客戶端生成 Proxy 實例,會把 Proxy 經過構造函數傳給 Stub 1,而後把 Stub 暴露給用戶,Stub 能夠決定要不要去調 Proxy。
在 spring 配置文件中按如下方式配置:
<dubbo:service interface="com.foo.BarService" stub="true" />
或
<dubbo:service interface="com.foo.BarService" stub="com.foo.BarServiceStub" />
Demo
package com.foo; public class BarServiceStub implements BarService { private final BarService barService; // 構造函數傳入真正的遠程代理對象 public (BarService barService) { this.barService = barService; } public String sayHello(String name) { // 此代碼在客戶端執行, 你能夠在客戶端作ThreadLocal本地緩存,或預先驗證參數是否合法,等等 try { return barService.sayHello(name); } catch (Exception e) { // 你能夠容錯,能夠作任何AOP攔截事項 return "容錯數據"; } } }
本地假裝 1 一般用於服務降級,好比某驗權服務,當服務提供方所有掛掉後,客戶端不拋出異常,而是經過 Mock 數據返回受權失敗。
在 spring 配置文件中按如下方式配置:
<dubbo:reference interface="com.foo.BarService" mock="true" />
或
<dubbo:reference interface="com.foo.BarService" mock="com.foo.BarServiceMock" />
Demo 在工程中提供 Mock 實現 :
package com.foo; public class BarServiceMock implements BarService { public String sayHello(String name) { // 你能夠僞造容錯數據,此方法只在出現RpcException時被執行 return "容錯數據"; } }
若是你的服務須要預熱時間,好比初始化緩存,等待相關資源就位等,可使用 delay 進行延遲暴露。
延遲 5 秒暴露服務
<dubbo:service delay="5000" />
延遲到 Spring 初始化完成後,再暴露服務 1
<dubbo:service delay="-1" />
務器端併發執行(或佔用線程池線程數)不能超過 10 個:
<dubbo:service interface="com.foo.BarService" executes="10" />
指定方法服務器端併發執行(或佔用線程池線程數)不能超過 10 個:
<dubbo:service interface="com.foo.BarService"> <dubbo:method name="sayHello" executes="10" /> </dubbo:service>
客戶端併發執行(或佔用鏈接的請求數)不能超過 10 個:
<dubbo:service interface="com.foo.BarService" actives="10" /> <dubbo:reference interface="com.foo.BarService" actives="10" />
Load Balance 均衡
配置服務的客戶端的 loadbalance
屬性爲 leastactive
,此 Loadbalance 會調用併發數最小的 Provider(Consumer端併發數)。
<dubbo:reference interface="com.foo.BarService" loadbalance="leastactive" />
<dubbo:service interface="com.foo.BarService" loadbalance="leastactive" />
服務端鏈接控制
限制服務器端接受的鏈接不能超過 10 個 1:
<dubbo:provider protocol="dubbo" accepts="10" />
或
<dubbo:protocol name="dubbo" accepts="10" />
客戶端鏈接控制
限制客戶端服務使用鏈接不能超過 10 個 2:
<dubbo:reference interface="com.foo.BarService" connections="10" />
或
<dubbo:service interface="com.foo.BarService" connections="10" />
若是 <dubbo:service>
和 <dubbo:reference>
都配了 connections,<dubbo:reference>
優先
延遲鏈接用於減小長鏈接數。當有調用發起時,再建立長鏈接。1
<dubbo:protocol name="dubbo" lazy="true" />
1. 注意:該配置只對使用長鏈接的 dubbo 協議生效
粘滯鏈接用於有狀態服務,儘量讓客戶端老是向同一提供者發起調用,除非該提供者掛了,再連另外一臺。
粘滯鏈接將自動開啓延遲鏈接,以減小長鏈接數。
<dubbo:protocol name="dubbo" sticky="true" />
經過令牌驗證在註冊中心控制權限,以決定要不要下發令牌給消費者,能夠防止消費者繞過註冊中心訪問提供者,另外經過註冊中心可靈活改變受權方式,而不需修改或升級提供者
能夠全局設置開啓令牌驗證:
<!--隨機token令牌,使用UUID生成--> <dubbo:provider interface="com.foo.BarService" token="true" />
或
<!--固定token令牌,至關於密碼--> <dubbo:provider interface="com.foo.BarService" token="123456" />
還可在服務級別、協議級別設置:
Dubbo 是經過 JDK 的 ShutdownHook 來完成優雅停機的,因此若是用戶使用 kill -9 PID
等強制關閉指令,是不會執行優雅停機的,只有經過 kill PID
時,纔會執行。
設置優雅停機超時時間,缺省超時時間是 10 秒,若是超時則強制關閉。
# dubbo.properties dubbo.service.shutdown.wait=15000
若是 ShutdownHook 不能生效,能夠自行調用,使用tomcat等容器部署的場景,建議經過擴展ContextListener等自行調用如下代碼實現優雅停機:
ProtocolConfig.destroyAll();
若是你想記錄每一次請求信息,可開啓訪問日誌,相似於apache的訪問日誌。注意:此日誌量比較大,請注意磁盤容量。
將訪問日誌輸出到當前應用的log4j日誌:
<dubbo:protocol accesslog="true" />
將訪問日誌輸出到指定文件:
<dubbo:protocol accesslog="http://10.20.160.198/wiki/display/dubbo/foo/bar.log" />
服務容器是一個 standalone 的啓動程序,由於後臺服務不須要 Tomcat 或 JBoss 等 Web 容器的功能,若是硬要用 Web 容器去加載服務提供方,增長複雜性,也浪費資源。
服務容器只是一個簡單的 Main 方法,並加載一個簡單的 Spring 容器,用於暴露服務。
服務容器的加載內容能夠擴展,內置了 spring, jetty, log4j 等加載,可經過容器擴展點進行擴展。配置配在 java 命令的 -D 參數或者 dubbo.properties
中。
容器類型
Spring Container
META-INF/spring
目錄下的全部 Spring 配置。配置 spring 配置加載位置:
dubbo.spring.config=classpath*:META-INF/spring/*.xml
Jetty Container
dubbo.jetty.port=8080
:配置 jetty 啓動端口dubbo.jetty.directory=/foo/bar
:配置可經過 jetty 直接訪問的目錄,用於存放靜態文件dubbo.jetty.page=log,status,system
:配置顯示的頁面,缺省加載全部頁面Log4j Container
dubbo.log4j.file=/foo/bar.log
:配置日誌文件路徑dubbo.log4j.level=WARN
:配置日誌級別dubbo.log4j.subdirectory=20880
:配置日誌子目錄,用於多進程啓動,避免衝突容器啓動
缺省只加載 spring
java com.alibaba.dubbo.container.Main
經過 main 函數參數傳入要加載的容器
java com.alibaba.dubbo.container.Main spring jetty log4j
經過 JVM 啓動參數傳入要加載的容器
java com.alibaba.dubbo.container.Main -Ddubbo.container=spring,jetty,log4j
經過 classpath 下的 dubbo.properties
配置傳入要加載的容器
dubbo.container=spring,jetty,log4j