暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

「DUBBO系列」服务降级源码分析

JAVA前线 2020-05-25
371

IT徐胖子原创本文未授权请勿转载


1 文章概述

假设服务提供者提供A服务,但是A服务并不稳定,那么如果服务消费者无法正常消费A服务就需要做降级处理,不再消费A服务而是返回一个mock值,这就是所谓服务降级。我们通过分析源码讲解服务降级策略,首先看一个消费者代码实例。

    public class Consumer {
    public static void main(String[] args) throws Exception {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "classpath*:META-INF/spring/dubbo-consumer.xml" });
    context.start();
    HelloService helloService = (HelloService) context.getBean("helloService");
    String result = helloService.sayHello("IT徐胖子");
    System.out.println("==========客户端收到结果==========" + result);
    }
    }
      <beans>
      <dubbo:application name="xpz-consumer" >
      <dubbo:registry address="zookeeper://127.0.0.1:2181" >
      <dubbo:reference id="helloService" interface="com.itxpz.dubbo.demo.provider.HelloService" >
      </beans>

      MockClusterInvoker正是服务降级核心

        // 通过动态代理机制生成代理对象Proxy
        // Proxy持有InvokerInvocationHandler
        // InvokerInvocationHandler持有invoker = MockClusterInvoker(FailoverClusterInvoker)
        HelloService helloService = (HelloService) context.getBean("helloService")


        2 服务降级策略

        2.1 不配置降级策略

          <dubbo:reference id="helloService" interface="com.itxpz.dubbo.demo.provider.HelloService" />


          2.2 强制降级策略

            <dubbo:reference id="helloService" mock="force:return 1" interface="com.itxpz.dubbo.demo.provider.HelloService" >


            2.3 异常降级策略

              <dubbo:reference id="helloService" mock="throw com.itxpz.BizException" interface="com.itxpz.dubbo.demo.provider.HelloService" >


              2.4 自定义降级策略

                package com.itxpz.dubbo.demo.consumer;
                import com.itxpz.dubbo.demo.provider.HelloService;
                public class HelloServiceMock implements HelloService {
                @Override
                public String sayHello(String name) throws Exception {
                return "mock";
                }
                }
                  <dubbo:reference id="helloService" mock="com.itxpz.dubbo.demo.consumer.HelloServiceMock" interface="com.itxpz.dubbo.demo.provider.HelloService" />


                  3 源码分析

                    public class MockClusterInvoker<T> implements Invoker<T> {


                    @Override
                    public Result invoke(Invocation invocation) throws RpcException {
                    Result result = null;


                    // 检查是否有mock属性
                    String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim();


                    // 没有mock属性直接执行消费逻辑
                    if (value.length() == 0 || value.equalsIgnoreCase("false")) {


                    // 服务消费默认执行FailoverClusterInvoker
                    result = this.invoker.invoke(invocation);
                    }


                    // 不执行消费逻辑直接返回
                    else if (value.startsWith("force")) {
                    if (logger.isWarnEnabled()) {
                    logger.warn("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl());
                    }
                    // 直接执行mock逻辑
                    result = doMockInvoke(invocation, null);
                    } else {
                    try {
                    // 服务消费默认执行FailoverClusterInvoker
                    result = this.invoker.invoke(invocation);
                    } catch (RpcException e) {
                    if (e.isBiz()) {
                    throw e;
                    }
                    if (logger.isWarnEnabled()) {
                    logger.warn("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e);
                    }
                    // 服务消费失败执行mock逻辑
                    result = doMockInvoke(invocation, e);
                    }
                    }
                    return result;
                    }
                    }




                    public class MockInvoker<T> implements Invoker<T> {


                    @Override
                    public Result invoke(Invocation invocation) throws RpcException {
                    String mock = getUrl().getParameter(invocation.getMethodName() + "." + Constants.MOCK_KEY);
                    if (invocation instanceof RpcInvocation) {
                    ((RpcInvocation) invocation).setInvoker(this);
                    }
                    if (StringUtils.isBlank(mock)) {
                    mock = getUrl().getParameter(Constants.MOCK_KEY);
                    }


                    if (StringUtils.isBlank(mock)) {
                    throw new RpcException(new IllegalAccessException("mock can not be null. url :" + url));
                    }
                    mock = normalizeMock(URL.decode(mock));


                    // <mock="force:return 1">直接包装返回结果
                    if (mock.startsWith(Constants.RETURN_PREFIX)) {
                    mock = mock.substring(Constants.RETURN_PREFIX.length()).trim();
                    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);
                    }
                    }


                    // <mock="throw">抛出异常
                    else if (mock.startsWith(Constants.THROW_PREFIX)) {
                    mock = mock.substring(Constants.THROW_PREFIX.length()).trim();
                    if (StringUtils.isBlank(mock)) {
                    throw new RpcException("mocked exception for service degradation.");
                    } else {
                    // 获取自定义异常
                    Throwable t = getThrowable(mock);
                    throw new RpcException(RpcException.BIZ_EXCEPTION, t);
                    }
                    }


                    // <mock="com.itxpz.HelloServiceMock">自定义mock策略
                    else {
                    try {
                    Invoker<T> invoker = getInvoker(mock);
                    return invoker.invoke(invocation);
                    } catch (Throwable t) {
                    throw new RpcException("Failed to create mock implementation class " + mock, t);
                    }
                    }
                    }
                    }


                    4 文章总结

                    本文我们分析了服务消费者降级策略源码,服务降级是分布式系统的重要策略,可以有效防止系统雪崩从而保护系统。


                    长按二维码关注更多精彩文章

                    文章转载自JAVA前线,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                    评论