客户端调用过程分析
当我们我们调用服务的具体方法时 : service.sayHello()
IHelloService helloService = (IHelloService) context.getBean("helloService");
// helloService =
// Proxy0(InvokerInvocationHandler(MockClusterInvoker(FailoverClusterInvoker()))))
helloService.sayHello();
会根据代理对象进行一层层的调用,
-
首先会从InvokerInvocationHandler进入到MockClusterInvoker中 ,
会根据是否配置了Mock机制进行不同的逻辑操作,主要是直接调用目标方法、直接调用Mock方法、先调用目标方法,当出现RPCException时,进行调用Mock方法。这是降级的策略
-
然后会进入到ClusterInvoker中,
- 在服务熔断中,默认是Failover(失败重试),此时会走FailoverClusterInvoker方法,根据不同的功能,会有不同的操作,Failover中会存在重试机制,如果失败后悔根据你是否配置了重试次数,如果没有重试次数,默认是再次重试两次
- 在进行调用时,会去获得一个服务,此时会从Directory 中获得维护的Invoker列表,并根据负载机制(随机、轮询、一致性hash、最少活跃数),去选择一个服务进行调用,
-
最终通过 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
开始主要有以下几步:
- 判断配置是否配置了mock 规则,按照规则进行调用,
- 调用到
FailoverClusterInvoker#doInvoke()
,这里是进行熔断处理,默认是failover:失败重试(2) - 获得到 Invoker 列表根据LoadBalance 规则进行负载
- 最终调用到
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(...);
}