dubbo 客户端调用过程分析

客户端调用过程分析
当我们我们调用服务的具体方法时 : service.sayHello()

IHelloService helloService = (IHelloService) context.getBean("helloService");
// helloService = 
// Proxy0(InvokerInvocationHandler(MockClusterInvoker(FailoverClusterInvoker()))))
helloService.sayHello();

会根据代理对象进行一层层的调用,

  1. 首先会从InvokerInvocationHandler进入到MockClusterInvoker中 ,

    会根据是否配置了Mock机制进行不同的逻辑操作,主要是直接调用目标方法、直接调用Mock方法、先调用目标方法,当出现RPCException时,进行调用Mock方法。这是降级的策略

  2. 然后会进入到ClusterInvoker中,

    1. 在服务熔断中,默认是Failover(失败重试),此时会走FailoverClusterInvoker方法,根据不同的功能,会有不同的操作,Failover中会存在重试机制,如果失败后悔根据你是否配置了重试次数,如果没有重试次数,默认是再次重试两次
    2. 在进行调用时,会去获得一个服务,此时会从Directory 中获得维护的Invoker列表,并根据负载机制(随机、轮询、一致性hash、最少活跃数),去选择一个服务进行调用,
  3. 最终通过 DubboInvoker 通过 Netty 进行与服务端进行通信

客户端调用过程

InvokerInvocationHandler 调用入口

public static void main(String[] args) throws IOException {
    ClassPathXmlApplicationContext classPathXmlApplicationContext =
        new ClassPathXmlApplicationContext("dubbo-client.xml");
    IHelloService helloService = (IHelloService) 
        	classPathXmlApplicationContext.getBean("helloService");
    // 因为 helloService 实际上是 Proxy0(InvokerInvocationHandler(MockClusterInvoker()))
    // 所以会走到 InvokerInvocationHandler.invoke() 中
    System.out.println(helloService.sayHello("World"));
}

客户端调用主要做了什么?

客户端对象拿到代理对象后,进行调用,调用时会根据熔断和降级的策略 以及获得提供方提供的所有服务列表根据负载均衡规则,进行服务调用,最终通过 DubboProtocol 调用 Netty 进行与服务端进行通信

com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker#invoke 开始主要有以下几步:

  1. 判断配置是否配置了mock 规则,按照规则进行调用,
  2. 调用到 FailoverClusterInvoker#doInvoke() ,这里是进行熔断处理,默认是failover:失败重试(2)
  3. 获得到 Invoker 列表根据LoadBalance 规则进行负载
  4. 最终调用到DubboInvoker#doInvoke() 调用Netty 与服务端进行通信
// MockClusterInvoker#invoke
// 远程调用 :根据 是否配置了 降级(mock) 进行调用
public Result invoke(Invocation invocation) throws RpcException {
    Result result = null;
    /*
    <dubbo:reference id="helloService"
    interface="com.guaoran.source.dubbo.demo.IHelloService"
    version="1.0.0"
    cluster="failfast"
    timeout="5000"
    mock="com.guaoran.source.dubbo.demo.MockServiceImpl"/>
    */

    // 获取 dubbo 配置文件中是否配置了 mock 机制
    String value = directory.getUrl().
        getMethodParameter
        (invocation.getMethodName(), Constants.MOCK_KEY, 
         Boolean.FALSE.toString()).trim();

    if (value.length() == 0 || value.equalsIgnoreCase("false")) {
        //no mock
        // 直接调用 invoker = 配置文件中的 cluster
        result = this.invoker.invoke(invocation);
    } else if (value.startsWith("force")) {
        if (logger.isWarnEnabled()) {
            logger.info("force-mock: " + 
                        invocation.getMethodName() + 
                        " force-mock enabled , url : " + 
                        directory.getUrl());
        }
        //force:direct mock
        // 表示强制调用 mock 的方法,不再调用原始的方法
        result = doMockInvoke(invocation, null);
    } else {
        //fail-mock
        try {
            // 调用原始的方法,如果出现 RpcException 异常 ,则执行 mock 方法
            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;
}
// FailoverClusterInvoker#doInvoke
public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
    List<Invoker<T>> copyinvokers = invokers;
    checkInvokers(copyinvokers, invocation);
    // 重试次数,默认两次, 加上第一次调用总共是三次,如果配置重试次数是0,则不进行重试,只走原始的一次调用
    int len = getUrl().getMethodParameter(invocation.getMethodName(), Constants.RETRIES_KEY, Constants.DEFAULT_RETRIES) + 1;
    if (len <= 0) {
        len = 1;
    }
    // retry loop.
    RpcException le = null; // last exception.
    List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyinvokers.size()); 
    Set<String> providers = new HashSet<String>(len);
    for (int i = 0; i < len; i++) {
        //重试时,进行重新选择,避免重试时invoker列表已发生变化.
        //注意:如果列表发生了变化,那么invoked判断会失效,因为invoker示例已经改变
        if (i > 0) {
            checkWhetherDestroyed();
            copyinvokers = list(invocation);
            //重新检查一下
            checkInvokers(copyinvokers, invocation);
        }
        // 随机负载机制 去获得一个服务进行调用
        Invoker<T> invoker = select(loadbalance, invocation, copyinvokers, invoked);
        invoked.add(invoker);
        RpcContext.getContext().setInvokers((List) invoked);
        try {
            Result result = invoker.invoke(invocation);

            // 如果成功,直接返回
            return result;
        } catch (RpcException e) {
            if (e.isBiz()) { // biz exception.
                throw e;
            }
            le = e;
        } catch (Throwable e) {
            le = new RpcException(e.getMessage(), e);
        } finally {
            providers.add(invoker.getUrl().getAddress());
        }
    }
    throw new RpcException(...);
}

client_transport_server

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值