什麼是服務降級?
當服務器壓力比較大的時候,我們可以通過服務降級,屏蔽掉一些非關鍵服務,給它們定義一個降級後的返回策略,從而降低核心業務的壓力。
通俗的說,服務降級就是在遠程調用失敗(例如超時)之後,直接採用降級措施,返回一個我們已經定義好的提示。例如,在12306搶票高峯時,明明票還有,但查詢列表總是空的,過了高峯之後再次查詢,又會恢復正常,這可能是因爲超時或者網絡問題導致查詢失敗,最後不得不採用了服務降級進行處理,給我們返回一個已經定義好的值。
如何實現服務降級
Dubbo 中有一個 mock 的配置,我們可以通過這個配置實現服務降級。其中,mock 的配置有兩種:
- 通過 boolean 值指定是否實行服務降級,其中默認爲 false,當配置爲 true 時,缺省通過在服務名後面加上 Mock 後綴的類來指定降級後的返回值
- 直接 return null,統一返回空
需要注意的是,mock 只會在非業務異常的時候執行,比如超時,又或者是網路異常。
測試
首先我們來看一下不做服務降級會是什麼後果,我們在服務提供者中故意令其超時,由於 Dubbo 默認超時時間爲1s,我們就令其睡眠兩秒,代碼如下:
package edu.szu.producer.serviceImpl;
import com.alibaba.dubbo.config.annotation.Service;
import edu.szu.api.service.NameService;
import org.springframework.stereotype.Component;
@Component
@Service
public class NameServiceImpl implements NameService {
@Override
public String updateName(String name) {
//讓其超時
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "遠程調用的值:" + name;
}
}
然後運行服務提供者與服務消費者,果不其然,直接報錯。
然後我們添加 return null 的降級設置,代碼如下,看看其效果
package edu.szu.consumer.serviceImpl;
import com.alibaba.dubbo.config.annotation.Reference;
import edu.szu.api.service.NameService;
import edu.szu.consumer.service.ChangeService;
import org.springframework.stereotype.Component;
@Component
public class ChangeServiceImpl implements ChangeService {
//定義服務降級的策略:直接返回空
@Reference(mock = "return null")
NameService nameService;
@Override
public String change(String name) {
return nameService.updateName(name);
}
}
顯然它會直接返回空,這需要我們做進一步的處理。需要注意的是,當我們將 mock 設置爲 return null 時,它不會進行遠程調用,而是直接返回一個空就行了。
在某些情況下,直接返回空對我們的用戶不太友好,這時我們可以給用戶返回一個我們之前定義好的值。首先我們在 api 模塊中指定一個服務降級的處理策略,其中這個處理類名缺省爲在服務名上加上 Mock 後綴,且應該與服務接口在同路徑下。
package edu.szu.api.service;
public class NameServiceMock implements NameService {
//定義服務降級的返回值
@Override
public String updateName(String name) {
return "服務降級了!";
}
}
然後在消費者中配置 mock 屬性爲 true。
package edu.szu.consumer.serviceImpl;
import com.alibaba.dubbo.config.annotation.Reference;
import edu.szu.api.service.NameService;
import edu.szu.consumer.service.ChangeService;
import org.springframework.stereotype.Component;
@Component
public class ChangeServiceImpl implements ChangeService {
//定義服務降級的策略
@Reference(mock = "true")
NameService nameService;
@Override
public String change(String name) {
return nameService.updateName(name);
}
}
然後我們發起一次遠程調用,由於調用超時,顯然是失敗的,但由於我們進行了服務降級,會返回我們指定的返回值。
另外,該方法與直接 return null 不同的是,如果我們的遠程調用成功了,不會執行服務降級,會返回遠程調用的結果,而 return null 事實上根本不進行遠程調用就直接返回空了。
進階
當然,我們也可以通過 Admin 控制檯來實現服務降級。
我們發現對服務可以進行屏蔽與容錯操作,其中,屏蔽表示對服務不發起遠程調用,直接返回空就行了;而容錯則表示在對該服務的方法調用失敗後,再返回空,這兩個是不同的。