dubbo服务降级
轉:
dubbo服務降級
1. 在 dubbo 管理控制臺配置服務降級
上圖的配置含義是:consumer 調用 com.zhang.HelloService 的方法時,直接返回 null,不發起遠程調用。
實際操作是:在 zk 的 /dubbo/com.zhang.HelloService/configurators 節點中添加了 override。
override://0.0.0.0/com.zhang.HelloService?category=configurators&dynamic=false&group=a&mock=force:return+null
2. 也可以通過代碼,進行服務降級:(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=consumer_app&mock=force:return+null"));
mock=force:return+null
表示消費方對該服務的方法調用都直接返回 null 值,不發起遠程調用。用來屏蔽不重要服務不可用時對調用方的影響。
mock=fail:return+null
表示消費方對該服務的方法調用在失敗后,再返回 null 值,不拋異常。用來容忍不重要服務不穩定時對調用方的影響。
dubbo 服務降級的真實含義:并不是對 provider 進行操作,而是告訴 consumer,調用服務時要做哪些動作。
3. 現在分析consumer端靜態配置mock, consumer中如何調用mock服務
用戶可以在<dubbo:reference>中配置mock屬性。如何配置自定義的mock,還沒有搞懂。以mock="force:return+null"為例,我們先分析dubbo默認的MockInvoker。
MockClusterInvoker邏輯:
// MockClusterInvoker
public Result invoke(Invocation invocation) throws RpcException {
Result result = null;
// 獲取<dubbo:reference>的mock屬性。
String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim();
if (value.length() == 0 || value.equalsIgnoreCase("false")){
//mock="" 或者 mock="false"
result = this.invoker.invoke(invocation);
} else if (value.startsWith("force")) {
//強制使用mock,如mock="force:return+null"
if (logger.isWarnEnabled()) {
logger.info("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl());
}
result = doMockInvoke(invocation, null);
} else {
//mock="fail:return+null" 或 mock="MyMock"
try {
result = this.invoker.invoke(invocation);
}catch (RpcException e) {
if (e.isBiz()) {
throw e;
} else {
if (logger.isWarnEnabled()) {
logger.info("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e);
}
//出現超時異常
result = doMockInvoke(invocation, e);
}
}
}
return result;
}
private Result doMockInvoke(Invocation invocation, RpcException e) {
Result result = null;
Invoker<T> minvoker;
List<Invoker<T>> mockInvokers = selectMockInvoker(invocation);
if (mockInvokers == null || mockInvokers.size() == 0){
//如果沒有配置自定義Mock,則使用默認MockInvoker
minvoker = (Invoker<T>) new MockInvoker(directory.getUrl());
} else {
minvoker = mockInvokers.get(0);
}
try {
//調用
result = minvoker.invoke(invocation);
} catch (RpcException me) {
if (me.isBiz()) {
result = new RpcResult(me.getCause());
} else {
throw new RpcException(me.getCode(), getMockExceptionMessage(e, me), me.getCause());
}
} catch (Throwable me) {
throw new RpcException(getMockExceptionMessage(e, me), me.getCause());
}
return result;
}
默認的MockInvoker:
// MockInvoker
public Result invoke(Invocation invocation) throws RpcException {
//獲取url中的sayHello.mock參數值
String mock = getUrl().getParameter(invocation.getMethodName() + "." + Constants.MOCK_KEY);
if (invocation instanceof RpcInvocation) {
((RpcInvocation) invocation).setInvoker(this);
}
if (StringUtils.isBlank(mock)){
//獲取mock屬性值
mock = getUrl().getParameter(Constants.MOCK_KEY);
}
if (StringUtils.isBlank(mock)){
throw new RpcException(new IllegalAccessException("mock can not be null. url :" + url));
}
//假定mock="force:return+null",處理后mock="return+null"
mock = normallizeMock(URL.decode(mock));
if (Constants.RETURN_PREFIX.trim().equalsIgnoreCase(mock.trim())){
RpcResult result = new RpcResult();
result.setValue(null);
return result;
} else if (mock.startsWith(Constants.RETURN_PREFIX)) {
//構造返回值
mock = mock.substring(Constants.RETURN_PREFIX.length()).trim();
mock = mock.replace('`', '"');
try {
Type[] returnTypes = RpcUtils.getReturnTypes(invocation);
Object value = parseMockValue(mock, returnTypes);
return new RpcResult(value);
} catch (Exception ew) {
throw new RpcException("mock return invoke error. method:" + invocation.getMethodName() + ", mock:" + mock + ", url: "+ url , ew);
}
} else if (mock.startsWith(Constants.THROW_PREFIX)) {
mock = mock.substring(Constants.THROW_PREFIX.length()).trim();
mock = mock.replace('`', '"');
if (StringUtils.isBlank(mock)){
throw new RpcException(" mocked exception for Service degradation. ");
} else { //用戶自定義類
Throwable t = getThrowable(mock);
throw new RpcException(RpcException.BIZ_EXCEPTION, t);
}
} else { //impl mock
try {
Invoker<T> invoker = getInvoker(mock);
return invoker.invoke(invocation);
} catch (Throwable t) {
throw new RpcException("Failed to create mock implemention class " + mock , t);
}
}
}
//mock=fail:throw
//mock=fail:return
//mock=xx.Service
private String normallizeMock(String mock) {
if (mock == null || mock.trim().length() ==0){
return mock;
} else if (ConfigUtils.isDefault(mock) || "fail".equalsIgnoreCase(mock.trim()) || "force".equalsIgnoreCase(mock.trim())){
mock = url.getServiceInterface()+"Mock";
}
if (mock.startsWith(Constants.FAIL_PREFIX)) {
mock = mock.substring(Constants.FAIL_PREFIX.length()).trim();
} else if (mock.startsWith(Constants.FORCE_PREFIX)) {
mock = mock.substring(Constants.FORCE_PREFIX.length()).trim();
}
return mock;
}
標簽: dubbo
總結
- 上一篇: Java 字符串转时间的前30分钟方法
- 下一篇: 降维之主成分分析法(PCA)