18.重试、provider下线、网络断开等容错怎么实现

case构造的方式

可以在DubboInvoker.doInvoke打断点,然后让provider下线,然后再继续执行刚才断点停住的地方等等构造异常场景。

如果有provider服务停掉, consumer端如何感知?再次启动刚停掉的provider呢

provider停掉会触发zk客户端的监听,监听对客户端的invoker列表进行刷新。
再次启动会触发 zk的监听,代码在ZkclientZookeeperClient

public IZkChildListener createTargetChildListener(String path, final ChildListener listener) {
		return new IZkChildListener() {
			public void handleChildChange(String parentPath, List<String> currentChilds)
					throws Exception {
				listener.childChanged(parentPath, currentChilds);
			}
		};
	}

然后再触发 com.alibaba.dubbo.registry.support.FailbackRegistry.doNotify(URL, NotifyListener, List)。
com.alibaba.dubbo.registry.integration.RegistryDirectory.refreshInvoker(List), 这是在zk的event线程完成的。
如果有provider停掉了 走一样的监听逻辑

同时,dubbo支持 定时检查provider的状态并进行重连,具体参见
com.alibaba.dubbo.remoting.transport.AbstractClient.initConnectStatusCheckCommand()
reconnectExecutorService.scheduleWithFixedDelay(connectStatusCheckCommand, reconnect, reconnect, TimeUnit.MILLISECONDS);

如果正在发服务的时候,provider停掉了,dubbo是如何处理的?

如果在发服务时,provider停掉了,那么此时会抛出异常,并在FailoverClusterInvoker doInvoke中捕获,
FailoverClusterInvoker支持调用失败时重试(可配置),此时达到再次重试的目的

配置获取的代码:

com.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(Invocation, List<Invoker>, LoadBalance)

int len = getUrl().getMethodParameter(invocation.getMethodName(), Constants.RETRIES_KEY, Constants.DEFAULT_RETRIES) + 1;

client在多次调用时,与provider端的连接是建立几次,在prodvider端服务状态有变化时呢?

NettyClient 的doOpen doConnect均在初始化的时候调用,有几个provider就调用几次,真正rpc调用服务的时候是不会再调用open与connect的。
上面这个说法不严格,因为看他发送消息的代码就知道了,每次发消息时还会检查下:

public void send(Object message, boolean sent) throws RemotingException {
    if (send_reconnect && !isConnected()){
        connect();
    }
    Channel channel = getChannel();
    //TODO getChannel返回的状态是否包含null需要改进
    if (channel == null || ! channel.isConnected()) {
      throw new RemotingException(this, "message can not send, because channel is closed . url:" + getUrl());
    }
    channel.send(message, sent);
}