本文主要學習dubbo服務的啟動檢查、集群容錯、服務均衡、線程模型、直連提供者、只定閱、只注冊等知識點,希望通過實例演示進一步理解和掌握這些知識點。
啟動檢查
Dubbo缺省會在啟動消費者時檢查依賴的服務是否可用,不可用時會拋出異常,阻止Spring初始化完成,以便上線時,能及早發現問題,默認check=true。
關閉沒有提供者時報錯
<dubbo:reference interface="com.mcweb.api.service.IUserService" id="userService" check="false" />
<!--或者采用全局配置-->
<dubbo:consumer check="false" />
check="false"表示不啟動服務提供者mcweb-logic,mcweb-web照樣能正常啟動。
關閉注冊訂閱失敗時報錯
<dubbo:registry check="false" />
check="false"表示,注冊中心未啟動,mcweb-web照樣能正常啟動。
集群容錯
基本概念
首先,我們要明確dubbo是怎么做集群的。dubbo的集群即同一個服務部署多台機或者同一台機不同端口注冊到注冊中心,消費者就通過訪問規則訪問集群內的不同節點的服務。
集群只需多個相同服務注冊相同的注冊中心。在每個服務提供者配置相同集群策略和訪問策略,對於消費者是透明,消費者通過框架決定訪問那個服務提供者。消費者通過注冊中心提供的服務端的協議信息,決定訪問哪個服務。
dubbo的集群容錯即當服務消費者調用服務提供者集群中的服務失敗時,Dubbo提供了多種容錯方案,缺省為failover重試(失敗自動切換,當出現失敗,重試其它服務器)。Dubbo提供的集群容錯模式有:
Failover Cluster(失敗自動切換,當出現失敗,重試其它服務器。(缺省))
Failfast Cluster(快速失敗,只發起一次調用,失敗立即報錯。)
Failsafe Cluster(失敗安全,出現異常時,直接忽略。)
Failback Cluster(失敗自動恢復,后台記錄失敗請求,定時重發。)
Forking Cluster(並行調用多個服務器,只要一個成功即返回。)
Broadcast Cluster(廣播調用所有提供者,逐個調用,任意一台報錯則報錯。)
詳細解析參考
http://dubbo.io/User+Guide-zh.htm#UserGuide-zh-%E9%9B%86%E7%BE%A4%E5%AE%B9%E9%94%99
集群模式配置
在《基於dubbo構建分布式項目與服務模塊》一文中,我們創建了服務消費者mcweb-web與服務提供者mcweb-logic,現在我們再增加兩個服務提供者,和mcweb-logic屬於同一個服務,便於區分,將模塊名稱命名為mcweb-logic-a,mcweb-logic-b。現在mcweb-logic,mcweb-logic-a,mcweb-logic-b都屬於同一個服務,均提供IUserService服務。需要將三個相同的服務以不同的端口注冊到zookeeper中並指定集群容錯模式,集群容錯模式也可以在服務提供者配置。
<!--\mcweb\mcweb-web\src\main\resources\spring\dubbo-consumer.xml-->
<dubbo:reference
interface="com.mcweb.api.service.IUserService"
id="userService"
check="false"
protocol="dubbo"
cluster="failover"
retries="2"
/>
<!---或者->
<!--\mcweb\mcweb-logic\src\main\resources\spring\dubbo-provider.xml-->
<dubbo:protocol name="dubbo" port="20880" />
<dubbo:service
interface="com.mcweb.api.service.IUserService"
ref="userService"
protocol="dubbo"
cluster="failover"
retries="2"
/>
運行服務集群
在《基於dubbo構建分布式項目與服務模塊》一文中,我們采用了tomcat容器來運行服務消費者和服務提供者,現在我們采用main方法來運行,這種方式通常在測試環境中使用。
<!--\mcweb\mcweb-logic\src\main\java\com\mcweb\logic\test\DubboServiceStart.java-->
public class DubboServiceStart { public static void main(String[] args) throws IOException { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:spring/applicationContext.xml"); System.out.println("mcweb-logic 服務已啟動..."); //為保證服務一直開着,利用輸入流的阻塞來模擬 System.in.read(); } }
分別以這種方式運行另外兩個服務。在dubbo管控台可以看到:
集群容錯測試
服務集群對消費者來說是透明的,消費者只需注明注冊中心和需要的服務即可,無需關注服務是單節點還是集群。因為在同一台機子上測試,將消費者的端口改為20883
<!--\mcweb\mcweb-web\src\main\resources\spring\dubbo-consumer.xml-->
<dubbo:protocol name="dubbo" port="20883"/>
現在我們來運行消費者。
<!--\mcweb\mcweb-web\src\main\java\com\mcweb\web\test\DubboConsumerStart.java-->
public class DubboConsumerStart { public static void main(String[] args) throws Exception { ApplicationContext ctx=new ClassPathXmlApplicationContext("classpath*:spring/applicationContext.xml"); System.out.println("mcweb-web 消費者已啟動..."); for(int i=0; i<1000;i++) { IUserService userService=(IUserService) ctx.getBean("userService"); User user = userService.query("testid"); System.out.println(i + ":" + user.getUserName()); Thread.sleep(1000); } } }
運行結果:
...
10:Get user from mcweb-logic-b
11:Get user from mcweb-logic
12:Get user from mcweb-logic-a
13:Get user from mcweb-logic-b
14:Get user from mcweb-logic-a
15:Get user from mcweb-logic
16:Get user from mcweb-logic
17:Get user from mcweb-logic
18:Get user from mcweb-logic-b
19:Get user from mcweb-logic
20:Get user from mcweb-logic
...
可見,默認情況下,dubbo服務集群是帶有負載均衡的(默認為random算法隨機調用),集群中的服務被均勻的調用,在cluster="failover"模式下,當調用失敗時,會嘗試調用其他服務器。可以在dubbo管控台中對服務進行“倍權”,“半權”,“禁用”等操作觀察消費者的調用情況。
負載均衡
基本概念
負載均衡(Load Balance)是分布式系統架構設計中必須考慮的因素之一,它通常指將請求/數據均勻分攤到多個操作單元(集群服務節點)上執行,負載均衡的關鍵在於均勻。dubbo在服務集群負載均衡時,提供了多種均衡策略,缺省為random隨機調用。
Random LoadBalance隨機,按權重設置隨機概率。
RoundRobin LoadBalance 輪循,按公約后的權重設置輪循比率。
LeastActive LoadBalance 最少活躍調用數,相同活躍數的隨機,活躍數指調用前后計數差。
ConsistentHash LoadBalance 一致性Hash,相同參數的請求總是發到同一提供者。
詳細參考
http://dubbo.io/User+Guide-zh.htm#UserGuide-zh-%E9%9B%86%E7%BE%A4%E5%AE%B9%E9%94%99
負載均衡配置
同理,負載均衡可以在消費者或者提供者中配置。
<!--\mcweb\mcweb-web\src\main\resources\spring\dubbo-consumer.xml-->
<dubbo:reference
interface="com.mcweb.api.service.IUserService"
id="userService"
check="false"
protocol="dubbo"
cluster="failover"
retries="2"
loadbalance="random"
/>
我們采用random隨機均衡算法,在dubbo管控台中設置mcweb-logic(192.168.2.1:20880),mcweb-logic-a(192.168.2.1:20881),mcweb-logic-b(192.168.2.1:20882)的權重分別為200,100,50。
看看mcweb-web的調用情況:
0:Get user from mcweb-logic-b
1:Get user from mcweb-logic-a
2:Get user from mcweb-logic-a
3:Get user from mcweb-logic-b
4:Get user from mcweb-logic-a
5:Get user from mcweb-logic
6:Get user from mcweb-logic
7:Get user from mcweb-logic-b
8:Get user from mcweb-logic-a
9:Get user from mcweb-logic-b
10:Get user from mcweb-logic
11:Get user from mcweb-logic-a
12:Get user from mcweb-logic-a
13:Get user from mcweb-logic-a
14:Get user from mcweb-logic
15:Get user from mcweb-logic
16:Get user from mcweb-logic
17:Get user from mcweb-logic
18:Get user from mcweb-logic-b
19:Get user from mcweb-logic-b
20:Get user from mcweb-logic
21次調用中,mcweb-logic調用了8次,mcweb-logic-a調用了7次,mcweb-logic-b調用了6次,符合權重越大,調用次數越多。隨着調用次數的增多,每個節點上的服務被調用的次數會逐漸趨向設置的權重所占的比率。
線程模型
基本概念
dubbo的線程模型關注的是“請求/響應”是直接在IO線程上執行還是分發到線程池上由線程中的線程去執行具體的服務。說明如下:
l 如果事件處理的邏輯能迅速完成,並且不會發起新的IO請求,則直接在IO線程上處理更快,因為減少了線程池調度。
l 如果事件處理邏輯較慢,或者需要發起新的IO請求,則必須派發到線程池,否則IO線程阻塞,將導致不能接收其它請求。
線程模型配置
線程模型通常在服務提供者的<dubbo:protocol>標簽中配置
<dubbo:protocol
name="dubbo"
port="20880"
dispatcher="all"
threadpool="fixed"
threads="100"
/>
dispatcher分發類型取值有:
l all 所有消息都派發到線程池。
l direct 所有消息都不派發到線程池,全部在IO線程上直接執行。
l message 只有請求響應消息派發到線程池。
l execution 只請求消息派發到線程池。
l connection 在IO線程上,將連接斷開事件放入隊列,有序逐個執行。
threadpool的取值有:
l fixed 固定大小線程池,啟動時建立線程,不關閉,一直持有。(缺省)
l cached 緩存線程池,空閑一分鍾自動刪除,需要時重建。
l limited 可伸縮線程池,但池中的線程數只會增長不會收縮。
詳情參考
http://dubbo.io/User+Guide-zh.htm#UserGuide-zh-%E7%BA%BF%E7%A8%8B%E6%A8%A1%E5%9E%8B
直連提供者
直連提供者,從字面上就知道,消費者繞過注冊中心直接連接服務提供者,這通常在開發測試中為了方便使用。
修改\mcweb\mcweb-web\src\main\resources\spring\dubbo-consumer.xml
<!-- 注冊中心地址 -->
<!-- <dubbo:registry protocol="zookeeper" address="192.168.2.129:2181" check="true"/> -->
<dubbo:reference
interface="com.mcweb.api.service.IUserService"
id="userService"
check="false"
protocol="dubbo"
cluster="failover"
retries="2"
loadbalance="random"
url="dubbo://127.0.0.1:20880"
/>
在<dubbo:reference>中配置url指向提供者,將繞過注冊中心,多個地址用分號隔開。注釋掉mcweb-web的直 <dubbo:registry ...> 直連接本地的mcweb-logic。看看日志
[DUBBO] Successed connect to server /192.168.2.1:20880 from NettyClient 192.168.2.1 using dubbo version 2.5.3, channel is
[DUBBO] Start NettyClient DESKTOP-HBGAL7B/192.168.2.1 connect to the server /192.168.2.1:20880,
[DUBBO] Refer dubbo service com.mcweb.api.service.IUserService from url dubbo://127.0.0.1:20880/com.mcweb.api.service.IUserService?
mcweb-web 消費者已啟動...
0:Get user from mcweb-logic
1:Get user from mcweb-logic
2:Get user from mcweb-logic
只訂閱
只訂閱是指正在開發中的服務提供者,只訂閱自己依賴的服務,而不注冊到注冊中心,通過直連自己依賴的服務來測試正在開發中的服務。這樣可以避免開發未完成的提供者注冊到注冊中心后影響其它消費者的運行的問題。
禁用注冊配置
<dubbo:registry protocol="zookeeper" address="192.168.2.129:2181" register="false"/>
只注冊
只注冊是指在兩個注冊中心中,服務提供者只向其中一個注冊中心注冊服務而不訂閱服務。這個又是為了解決什么問題呢,先看下圖
服務A和服務B都注冊到了兩個注冊中心中,且都依賴於服務C(需要服務C都在兩個注冊中心注冊),
服務C又依賴服務D (服務C只需要訂閱zookeeper2的的D服務,服務D注冊到zookeeper2而不從zookeeper2訂閱服務)。
禁用訂閱配置
<dubbo:registry protocol="zookeeper" address="192.168.2.129:2181" subscribe="false"/>
本文到此,后面我們繼續學習多注冊中心、服務分組等內容。