Dubbo的服务降级策略剖析

1 服务降级策略概述

设置Dubbo服务降级策略的主要目的,简单来说就是为了实现对指定服务的请求可以不处理或者简单处理。服务降级策略主要有以下两种:

(1)force:return策略。服务消费端不进行远程调用,直接返回mock值。

mock = "force:return mock值" 

用来屏蔽非核心服务不可用时对调用方的影响。

(2)fail:return策略。当调用远程接口失败的时候,返回mock值,不抛异常。

mock = "fail:return mock值"

用来容忍非核心服务不稳定时对调用方的影响。

服务降级主要用在以下场景:

  • 当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务有策略的降低服务级别,以释放服务器资源,保证核心任务的正常运行。
  • 当服务响应超时或连接请求超时,不用继续等下去,而采用降级措施,以防止分布式服务发生雪崩效应。
  • 在大促销之前通过降级开关关闭推荐、评价等对主流程没有影响的功能。大促销完毕后,再进行恢复。
  • 在秒杀这种流量比较集中并且流量特别大的情况下,因为突发访问量特别大可能会导致系统支撑不了。这个时候可以采用限流来限制访问量,当达到阀值时,后续的请求被降级。

总的来说,服务降级策略主要用在保障核心服务的可用性,防止分布式服务发生雪崩效应,以及在服务器压力剧增或服务响应超时等情况下保证服务的正常运行。

2 设置服务降级策略

设置服务降级策略的主要方式有以下两种:

(1)通过dubbo控制台设置指定服务的降级策略。

(2)在服务消费端设置接口级别或方法级别的服务降级策略。举例如下。

设置接口级别的降级策略:

@Reference(mock = "fail:return null")
private TestService testService;

或者

<dubbo:reference id="testService" interface="com.hn.TestService" 
protocol="dubbo"  mock="force:return null"/>

设置方法级别的降级策略:

<!-- 对getUserList方法进行降级,其它方法正常调用 -->
<dubbo:reference id="testService" interface="com.hn.TestService" protocol="dubbo">
    <dubbo:method name="getUserList" mock="fail:return null"/>
</dubbo:reference>

3 服务降级策略过程剖析

在服务消费端发起远程调用的过程中,服务消费端首先调用MockClusterInvoker的invoker()方法使用服务降级策略。当不是“force:return策略”时,将继续调用DubboInvoker的invoker()方法发起远程调用。

MockClusterInvoker的invoker()具体实现如下所示。

public Result invoke(Invocation invocation) throws RpcException {
    Result result;

    String value = getUrl().getMethodParameter(RpcUtils.getMethodName(invocation), MOCK_KEY, Boolean.FALSE.toString()).trim();
    if (ConfigUtils.isEmpty(value)) {
        //no mock
        result = this.invoker.invoke(invocation);
    } else if (value.startsWith(FORCE_KEY)) {
        if (logger.isWarnEnabled()) {
            logger.warn(CLUSTER_FAILED_MOCK_REQUEST,"force mock","","force-mock: " + RpcUtils.getMethodName(invocation) + " force-mock enabled , url : " + getUrl());
        }
        //force:direct mock
        result = doMockInvoke(invocation, null);
    } else {
        //fail-mock
        try {
            result = this.invoker.invoke(invocation);

            //fix:#4585
            if (result.getException() != null && result.getException() instanceof RpcException) {
                RpcException rpcException = (RpcException) result.getException();
                if (rpcException.isBiz()) {
                    throw rpcException;
                } else {
                    result = doMockInvoke(invocation, rpcException);
                }
            }

        } catch (RpcException e) {
            if (e.isBiz()) {
                throw e;
            }

            if (logger.isWarnEnabled()) {
                logger.warn(CLUSTER_FAILED_MOCK_REQUEST,"failed to mock invoke","","fail-mock: " + RpcUtils.getMethodName(invocation) + " fail-mock enabled , url : " + getUrl(),e);
            }
            result = doMockInvoke(invocation, e);
        }
    }
    return result;
}


private Result doMockInvoke(Invocation invocation, RpcException e) {
    Result result;
    Invoker<T> mockInvoker;

    RpcInvocation rpcInvocation = (RpcInvocation)invocation;
    rpcInvocation.setInvokeMode(RpcUtils.getInvokeMode(getUrl(),invocation));

    List<Invoker<T>> mockInvokers = selectMockInvoker(invocation);
    if (CollectionUtils.isEmpty(mockInvokers)) {
        mockInvoker = (Invoker<T>) new MockInvoker(getUrl(), directory.getInterface());
    } else {
        mockInvoker = mockInvokers.get(0);
    }
    try {
        result = mockInvoker.invoke(invocation);
    } catch (RpcException mockException) {
        if (mockException.isBiz()) {
            result = AsyncRpcResult.newDefaultAsyncResult(mockException.getCause(), invocation);
        } else {
            throw new RpcException(mockException.getCode(), getMockExceptionMessage(e, mockException), mockException.getCause());
        }
    } catch (Throwable me) {
        throw new RpcException(getMockExceptionMessage(e, me), me.getCause());
    }
    if (setFutureWhenSync || rpcInvocation.getInvokeMode() != InvokeMode.SYNC) {
        // set server context
        RpcContext.getServiceContext().setFuture(new FutureAdapter<>(((AsyncRpcResult)result).getResponseFuture()));
    }
    return result;
}

4 参考文献

(1)https://www.cnblogs.com/studyjobs/p/16390503.html

(2)https://www.cnblogs.com/xfeiyun/p/16070538.html

相关推荐

  1. Dubbo服务降级策略剖析

    2024-01-13 08:54:02       40 阅读
  2. Dubbo集群容错策略剖析

    2024-01-13 08:54:02       31 阅读
  3. 服务降级策略及其在Spring Boot中实现

    2024-01-13 08:54:02       50 阅读
  4. DubboCluster策略与Directory实现

    2024-01-13 08:54:02       10 阅读
  5. 怎么直连某个服务器dubbo服务

    2024-01-13 08:54:02       14 阅读
  6. 服务熔断、降级和限流

    2024-01-13 08:54:02       26 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-13 08:54:02       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-13 08:54:02       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-13 08:54:02       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-13 08:54:02       18 阅读

热门阅读

  1. vue表格插件vxe-table导出 excel

    2024-01-13 08:54:02       40 阅读
  2. Spark十:故障排除

    2024-01-13 08:54:02       31 阅读
  3. static关键字的作用

    2024-01-13 08:54:02       43 阅读
  4. C语言-蓝桥杯算法提高VIP-产生数

    2024-01-13 08:54:02       35 阅读
  5. xdoj购票系统(多次循环)

    2024-01-13 08:54:02       31 阅读
  6. VSCODE插件开发API

    2024-01-13 08:54:02       29 阅读
  7. 孩子兄弟结构体【】

    2024-01-13 08:54:02       37 阅读
  8. Apache配置ssl证书-实现https访问

    2024-01-13 08:54:02       30 阅读
  9. Memcache未授权访问漏洞修复

    2024-01-13 08:54:02       43 阅读