Dubbo的高級特性
1、dubbo序列化
1.1、序列化、反序列化的介紹
- 序列化:把對象轉換為字節序列的過程稱為對象的序列化。
- 反序列化:把字節序列恢復為對象的過程稱為對象的反序列化。
先來思考兩個問題:
- 普通的Java對象的生命周期是僅限于一個JVM中的,只要JVM停止,這個對象也就不存在了,下次JVM啟動我們還想使用這個對象怎么辦呢?
- 或者我們想要把一個對象傳遞給另外一個JVM的時候,應該怎么做呢?
這兩個問題的答案分別是:
- 將該對象進行序列化,然后保存在文件中,
- 將對象序列化后通過網絡傳輸到另一個JVM,由另外一個JVM反序列化成一個對象,然后供JVM使用。
對象序列化就是將一個存在內存中的對象,轉換為可存儲或者可傳輸的二進制流,并且根據序列化的規則可以進行反序列化。
(一般來說需要保存的對象信息包括類的全限定名稱、未被transparent修飾的字段值,將這些信息按照一定的規則轉換為二進制之后進行網絡傳輸,在接收到的一端,就可以根據這些信息先實例化這個類對應的對象,然后將對應的屬性值填入新構造的對象,在使用者看來就是使用的原來的對象。)
1.2、dubbo序列化
dubbo支持很多種通信協議,其中dubbo協議作為默認的通信協議。dubbo 調用是需要跨 JVM,需要進行網絡通信,這就需要使用到序列化與反序列化。
dubbo 的消費者和服務提供者之間進行傳遞的數據都需要進行序列化。我們有時可能看到 dubbo 的消費者和提供者使用字符串進行數據傳遞,好像不需要做什么序列化操作,實際上這是因為 String 類本身就已經實現了序列化接口了。所以如果傳遞的參數即消費者傳遞的參數或者提供者返回的數據是我們自己定義的一些實體類的話,我們需要對該類手動實現序列化。
dubbo 中進行序列化的方式很簡單,只需該類實現 Serializable 即可。
比如消費者和提供者之間通過 User 類來進行數據傳遞,比如提供者方法接收一個 User 類做參數,或者提供者返回的數據是一個 User 類,則 User 類需要實現序列化。示例如下:
import java.io.Serializable; public class User implements Serializable { private String name; private int age; private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
dubbo 中消費者和提供者之間傳遞的數據未實現序列化的話,調用提供者的接口會直接報錯。
2、dubbo服務本地緩存(地址緩存)
根據官方圖,dubbo調用者需要通過注冊中心(例如:ZK)注冊信息,獲取提供者,但是如果頻繁往ZK獲取信息,肯定會存在單點故障問題(即注冊中心掛了就全掛了),所以dubbo提供了將提供者信息緩存在本地的方法。
Dubbo在訂閱注冊中心的回調處理邏輯當中會保存服務提供者信息到本地緩存文件當中(同步/異步兩種方式),以url緯度進行全量保存。Dubbo在服務引用過程中會創建registry對象并加載本地緩存文件,會優先訂閱注冊中心,訂閱注冊中心失敗后會訪問本地緩存文件內容獲取服務提供信息。
所以說如果注冊中心掛了,服務仍然是可以訪問和被訪問的。當如果是訪問新服務的話就不行,因為并沒有把新服務的地址緩存起來。
3、超時與重試
3.1、服務超時
如果服務器的提供者發生了故障,服務消費者在調用服務提供者的時候會發生阻塞、等待的情形,如果服務消費者一直等待下去,消費者會浪費大量資源,可能導致消費者也不可用。dubbo 利用超時機制來解決這個問題,設置一個超時時間,在這個時間段內,無法完成服務訪問,則自動斷開連接。
超時原因:
- 消費者:當消費者發起一次請求后,如果在規定時間內未得到服務端的響應則直接返回超時異常,但服務端的代碼依然在執行。
- 生產者:消費端發起一次請求后,一直等待服務端的響應,服務端在方法執行到指定時間后如果未執行完,此時返回一個超時異常給到消費端。
在 dubbo 中使用 timeout 屬性來配置超時時間,默認值是 1000,單位毫秒。在服務端和消費端都可以設置超時時間,但是服務消費者在調用的時候,會根據 timeout 配置的優先級,來獲取最終的超時配置時間。
超時配置優先級為:
- 消費者Method > 提供者method > 消費者Reference > 提供者Service > 消費者全局配置provider > 提供者全局配置consumer。
3.1.1、配置服務超時時間
1)在接口層面配置
- 在服務提供者的實現上配置
@Service(timeout = 10000) public class HelloServiceImpl implements HelloService { { ... }
- 在消費者調用方加
@Reference(timeout = 10000) private HelloService helloService;
2)全局配置
配置分別作為生產者和消費者時的超時時間,如下:
dubbo.provider.timeout = 10000
dubbo.consumer.timeout = 10000
3.2、重試
Dubbo 服務消費者在嘗試調用一次服務之后,如出現非業務異常(服務突然不可用、超時等),Dubbo 默認會進行額外的最多2次重試。默認是重試2次,加上初始一次,即總共實際上會調用提供者3次。
3.2.1、配置服務超時時間
重試次數可以使用 retries=重試次數來設置。
1)在接口層面配置
- 在服務提供者的實現上配置
@Service(retries=2) public class HelloServiceImpl implements HelloService { ... }
- 在消費者調用方加
@Reference(retries= 10000) private HelloService helloService;
2)全局配置
配置分別作為生產者和消費者時的重試次數,如下:
spring.dubbo.consumer.retries=1 spring.dubbo.provider.retries=2
4、服務多版本
在 dubbo 中,如果某個服務的功能出現變更或者出了新功能,可以通過版本號來控制先讓一部分用戶使用新功能,用戶反饋沒問題時,再將所有用戶遷移到新功能。dubbo 中使用version 屬性來設置和調用同一個接口的不同版本。
服務提供者通過 version 實現一個服務多個版本,如下:
@Service(version = "v1.0") public class UserServiceImpl implements UserService { ... }
@Service(version = "v2.0") public class UserServiceImpl2 implements UserService { ... }
服務消費者通過 version 來調用指定版本的接口,如下:
@Reference(version = "v2.0")//遠程注入 private UserService userService;
5、服務負載均衡
Dubbo提供了4種均衡策略,默認為Random(隨機調用)
- Random LoadBalance(隨機,按照權重的設置隨機概率)
- RoundRobin LoadBalance(輪詢,按照權重設置輪詢比率)
- LeastActive LoadBalance(最少活躍數,響應快的提供者接受越多請求,響應慢的接受越少請求)
- ConsistentHash LoadBalance(一致性Hash,相同參數的請求總是發到同一個服務提供者(相同參數默認是指請求的第一個參數)。攜帶相同的參數總是發送的同一個服務提供者,若服務掛了,則會基于虛擬節點平攤到其他提供者上)
負載均衡策略配置參考:https://blog.csdn.net/liuhenghui5201/article/details/108519253
xml 方式配置:
1)服務端配置
- 服務級別
<dubbo:service interface="..." loadbalance="roundrobin" />
- 方法級別
<dubbo:reference interface="..." loadbalance="roundrobin" />
2)消費端配置
- 服務級別
<dubbo:reference interface="..." loadbalance="roundrobin" />
- 方法級別
<dubbo:reference interface="..."> <dubbo:method name="..." loadbalance="roundrobin"/> </dubbo:reference>
6、集群容錯
在微服務環境中,為了保證服務的高可用,很少會有單點服務出現,服務通常都是以集群的形式出現。在dubbo遠程調用過程中,被調用的遠程服務并不是每時刻都保持良好的狀態,當某個服務調用出現異常時候(比如網絡抖動、服務短暫不可用),都需要進行容錯,就需要到了集群容錯機制。
dubbo 中有以下集群容錯模式:
- Failover Cluster:失敗重試。默認值。當出現失敗,重試其它服務器 ,默認重試2次,使用 retries 配置。一般用于讀操作
- Failfast Cluster :快速失敗,只發起一次調用,失敗立即報錯。通常用于寫操作。
- Failsafe Cluster :失敗安全,出現異常時,直接忽略。返回一個空結果。
- Failback Cluster :失敗自動恢復,后臺記錄失敗請求,定時重發。通常用于消息通知操作。
- Forking Cluster :并行調用多個服務器,只要一個成功即返回。
- Broadcast Cluster :廣播調用所有提供者,逐個調用,任意一臺報錯則報錯。
可參考官網:https://dubbo.apache.org/zh/docsv2.7/user/examples/fault-tolerent-strategy/
7、服務降級
dubbo開發中,通常是微服務架構,那么在使用過程中可能會遇到多種問題:
- 多個服務之間可能由于服務沒有啟動或者網絡不通,調用中會出現遠程調用失敗
- 服務請求過大,需要停止調用其他部分不重要服務以保證本身核心業務的正常運行;
以上兩個問題可以使用Dubbo的服務降級來實現,即:在其他服務宕掉或者并發數太高導致的RpcException異常時,進行友好的處理或者提示,而不是內部報錯導致系統不可用。
7.1、配置服務降級
Dubbo可以通過服務降級功能臨時屏蔽某個出錯的非關鍵性服務,并定義降級后的返回策略。 我們可以向注冊中心寫入動態配置覆蓋規則:
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); registry.register(URL.valueOf("override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&mock=force:return+null"));
也可以通過配置文件進行定義。
<dubbo:reference id="iUser" interface="com.dubbosample.iface.IUser" timeout="1000" check="false" mock="return null">
配置 mock 有以下幾種形式:
<dubbo:reference mock="true" .../> <dubbo:reference mock="com.xxxx" .../> <dubbo:reference mock="return null" .../> <dubbo:reference mock="throw xxx" .../> <dubbo:reference mock="force:return .." .../> <dubbo:reference mock="force:throw ..." .../>
mock="force:return null":表示消費方對該服務的方法調用都直接返回null值,不發起遠程調用。用來屏蔽不重要服務不可用時對調用方的影響。- 還可以改為
mock="fail:return null":表示消費方對該服務的方法調用在失敗后,再返回null。用來容忍不重要服務不穩定時對調用方的影響。
也可通過 dubbo 的管理控制臺(如 dubbo-admin)進行配置。
參考:http://www.rzrgm.cn/hup666/p/13472829.html

浙公網安備 33010602011771號