Dubbo 常用配置
高可用-zookeeper宕機與dubbo直連
註冊中心宕機,還可以消費dubbo暴露的服務
- 監控中心宕機了,不影響使用,只會丟失部分資料的採集
- 資料庫宕機了,zookeeper仍然可以通過快取查詢服務提供者列表,但是不能註冊新服務
- 註冊中心叢集對等叢集,任何一臺掛掉後都會切換到另一臺
- 註冊中心全部宕機,仍可一通過使用本地快取進行通訊
- 服務提供者提供無狀態的服務,任意一臺宕機,都不影響使用
- 服務提供者全部宕機後,服務消費者無法正常使用,無限次重連等待服務提供者的恢復
通過dubbo直連的方式
繞開註冊中心直連服務提供者
@Reference(url="127.0.0.1:20888") // dubbo的註解 UserService userService; public List<UserAddress> initOrder(String userId) { return userService.getUserAddressList("1"); }
叢集負載均衡
同一種服務提供者存在多份時需要負載均衡策略, loadbalance
Random LoadBalance
隨機負載均衡, 按照權重設定隨機概率,隨機呼叫量越大,分佈越均勻,有利於動態調整提供者的權重
例: UserService一共三臺,我們根據實際的機器效能給這三個機器新增不同的權重
userService1 weight=100
userService2 weight=200
userService3 weight=300
這樣這三臺機器被隨機呼叫到的比例就是1:2:3
這是Dubbo預設的負載均衡機制
@SPI("random") public interface LoadBalance { @Adaptive({"loadbalance"}) <T> Invoker<T> select(List<Invoker<T>> var1, URL var2, Invocation var3) throws RpcException; }
RoundRobin LoadBalace
假如同樣存在三臺相同的服務提供者, 不設定權重的話,消費者的會被均勻的按瞬間分發到這個三臺機器上123123123...
輪詢, 按照公約後的權重值,設定查詢比率 , 存在慢的提供者請求累積的問題, 這種方式的訪問順序也是提前就知道的,只不過新增上了權重的之後的順序, 原來的123123... 可能變成了 123333
LeastActive LoadBalance
最少活躍呼叫數, 活躍數指的是呼叫前後的計時差,使慢的提供者接受更少的請求
當用戶的請求會先查詢服務提供者列表中,然後選擇活躍數最低的,也就是上次響應時間最短的機器
ConsistentHash LoadBalance
一致性Hash, 使相同引數的請求總是發到同一個提供者上,當某一臺提供者掛掉時,原本該傳送到這個服務提供者的請求會平攤到其他提供者身上,不會產生巨大的動盪
- 預設只對第一個引數 Hash,如果要修改,請配置
<dubbo:parameter key="hash.arguments" value="0,1" />
- 預設用 160 份虛擬節點,如果要修改,請配置
<dubbo:parameter key="hash.nodes" value="320" />
負載均衡的修改方式
- 配置檔案版
服務端服務級別
<dubbo:service interface="..." loadbalance="roundrobin" />
客戶端服務級別
<dubbo:reference interface="..." loadbalance="roundrobin" />
服務端方法級別
<dubbo:service interface="...">
<dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:service>
客戶端方法級別
<dubbo:reference interface="...">
<dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:reference>
- 註解版
@Reference(loadbalance = "random")
@Reference(loadbalance = "roundrobin")
@Reference(loadbalance = "leastactive")
@Reference(loadbalance = "consistenthash")
權重的新增
- 硬編碼
在暴露服務是,在@Service註解上邊新增 weight屬性 @Service(weight="200")
- 通過控制檯,手動設定服務提供者的權重
服務降級
什麼是服務降級?
在伺服器壓力劇增的情況下,根據實際的業務情況及流量,對一些服務和頁面進行有策略的不處理或者換種簡單方式處理的方式, 從而達到釋放系統資源,維持系統核心功能的正常運作
實現: 想註冊中心寫入動態配置規則
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"));
- 實現方式1
上面配置的最後一條URL上,mock=force:return+null
,表示在服務消費者層面直接對使用者的呼叫返回空,不行轉發處理
- 實現方式2
最後的url位置還可以寫成mock=fail:return+null
,表示消費者在對服務的呼叫方法失敗後才返回null,用來緩衝服務呼叫不穩定時,對服務呼叫方的影響
``
如圖在控制檯進行視覺化介面消費者模組實現服務降級
叢集容錯
服務在呼叫失敗時,Dubbo提供了很多種容錯方案
Failover Cluster(預設)
failover cluster 失敗自動切換,當出現失敗,重試其它伺服器,但重試會帶來更長延遲。可通過 retries="2" 來設定重試次數(不含第一次)。
重試次數配置如下:
<dubbo:service retries="2" />
或
<dubbo:reference retries="2" />
或
<dubbo:reference>
<dubbo:method name="findFoo" retries="2" />
</dubbo:reference>
Failfast Cluster
快速失敗,只發起一次呼叫,失敗立即報錯。通常用於非冪等性的寫操作,比如新增記錄。
Failsafe Cluster
失敗安全,出現異常時,直接忽略。通常用於寫入審計日誌等操作。
Failback Cluster
失敗自動恢復,後臺記錄失敗請求,定時重發。通常用於訊息通知操作。
Forking Cluster
並行呼叫多個伺服器,只要一個成功即返回。通常用於實時性要求較高的讀操作,但需要浪費更多服務資源。可通過 forks="2" 來設定最大並行數。
Broadcast Cluster
廣播呼叫所有提供者,逐個呼叫,任意一臺報錯則報錯 [2]。通常用於通知所有提供者更新快取或日誌等本地資源資訊。
叢集模式配置
按照以下示例在服務提供方和消費方配置叢集模式
<dubbo:service cluster="failsafe" />
或
<dubbo:reference cluster="failsafe" />
整合 hystrix 做服務容錯
hystrix 旨在通過控制遠端系統,服務和第三方的節點,從而對延遲和故障提供更強大的容錯能力,Hystrix同時具備回退機制和斷路器能力功能的執行緒和訊號隔離,請求快取,請求打包已經監控和配置的功能
- 斷路器可以實現快速失敗,當它在一段時間內檢測到許多類似的錯誤(例如超時),就會在之後的一段時間內,強迫對該服務的呼叫快速失敗,即不再請求所依賴的服務。這樣,應用程式就不須浪費CPU時間去等待長時間的超時。
- 斷路器也可以自動診斷依賴的服務是否已經恢復正常。
hytrix的隔離策略有兩種:
- THREAD 執行緒隔離,使用這種方法HystrixCommand將會在單獨的執行緒上執行,併發請求收到執行緒數量的影響
- SEMAPHORE 訊號量隔離, 使用這種方法,HystrixComand將會在呼叫執行緒上執行,併發請求受到訊號量的個數限制
Hystrix預設的保護級別是THREAD,它出來超時保護還有額外的保護,一般當系統的負載特別大,每秒幾百併發時,才選擇訊號量隔離,正常情況下使用預設的隔離級別
可以使用execution.isolation.strategy屬性指定隔離策略。
@HystrixCommand(fallbackMethod = "notfindback", commandProperties=@HystrixProperty(name="execution.isolation.strategy", value="SEMAPHORE") )
public User findById( Long id)
public User notfindback(Long id)
{
User user = new User();
user.setId(0L);
return user;
}
編碼實現:
- 配置,服務提供者和服務消費者,雙方都新增Spring-cloud-starter-hystrix
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
- 服務提供者和消費者同時在啟動類上新增開啟此項功能
@EnableDubbo
@EnableHystrix
@SpringBootApplication
public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class);
}
}
- 對服務提供者對外暴露的介面實現進行改寫
@Component
@Service //使用dubbo的Service 對外保留服務
public class UserServiceImpl implements UserService {
// 新增這個註解,將當期方法,交給Hystrix進行代理,當出現異常時,進行容錯處理
@HystrixCommand
public List<UserAddress> getUserAddressList(String userId) {
UserAddress a1= new UserAddress(1,"張三","北京市朝陽區");
UserAddress a2= new UserAddress(2,"李四","山東濟南");
if (Math.random()>0.5){
throw new RuntimeException();
}
return Arrays.asList(a1,a2);
}
}
- 改寫服務消費者遠端過程呼叫的方法
public class UserServiceImpl implements UserService{
// 注入這個被服務提供者支援的介面
@Reference
private final UserService userService;
// 提供建構函式
public UserServiceImpl(UserService userService) {
this.userService = userService;
}
@Override
@HystrixCommand(fallbackMethod = "correct") // 當出現錯誤時,回撥correct方法
public List<UserAddress> getUserAddressList(String userId) {
// 判空
if (!StringUtils.isEmpty(userId)){
System.err.println();
return userService.getUserAddressList(userId);
}
return null;
}
public List<UserAddress> correct(String userId) {
return Collections.singletonList(new UserAddress(9, "correct", "correct"));
}
}