先看下consumer端发起调用时的链路流程:

 +---------------------------+            +---------------------------+            +---------------------------+
| helloService | | proxy | | InvokerInvocationHandler |
| sayHello +----------> | sayHello +----------> | invoke |
| | | | | proxy method args |
+---------------------------+ +---------------------------+ +-------------+-------------+
|
|
+---------------------------------+
| | |
| +------------v--------------+ |
| | MockClusterInvoker | |
| | invoke | |
| | | |
| +------------+--------------+ |
| | |
| | |
| | |
+---------------------------+ +---------------------------+ | +------------v--------------+ |
| Router | | RegistryDirectory | | | FailoverClusterInvoker | |
| route | <----------+ list | <-----------+ invoke | |
| MockInVokersSelector | | INVOCATION-->List INVOKER | | | | |
+------------+--------------+ +---------------------------+ | +---------------------------+ |
| | |
| +---------------------------------+
| cluster invoke,分布式调用容错机制也是在这做
|
|
|
|
|
+-------------v-------------+ +---------------------------+ +---------------------------+
| RandomLoadBalance | |InvokerDelegate | | ListenerInvokerWrap |
| select +-----------> |invoke +-----------> | invoke |
| List INVOKER-->INVOKER | | | | |
+---------------------------+ +---------------------------+ +---------------------------+

1. 引入zookeeper作为注册中心后,服务查找过程

从建立spring到netty client建立连接的调用栈:

NettyClient.doOpen() line: 66

NettyClient(AbstractClient).(URL, ChannelHandler) line: 94

NettyClient.(URL, ChannelHandler) line: 61

NettyTransporter.connect(URL, ChannelHandler) line: 37

Transporter$Adpative.connect(URL, ChannelHandler) line: not available

Transporters.connect(URL, ChannelHandler...) line: 67

HeaderExchanger.connect(URL, ExchangeHandler) line: 37

Exchangers.connect(URL, ExchangeHandler) line: 102

DubboProtocol.initClient(URL) line: 378

DubboProtocol.getSharedClient(URL) line: 344

DubboProtocol.getClients(URL) line: 321

DubboProtocol.refer(Class, URL) line: 303

ProtocolListenerWrapper.refer(Class, URL) line: 65

ProtocolFilterWrapper.refer(Class, URL) line: 62

Protocol$Adpative.refer(Class, URL) line: not available

RegistryDirectory.toInvokers(List) line: 405

RegistryDirectory.refreshInvoker(List) line: 228

RegistryDirectory.notify(List) line: 196

ZookeeperRegistry(AbstractRegistry).notify(URL, NotifyListener, List) line: 449

ZookeeperRegistry(FailbackRegistry).doNotify(URL, NotifyListener, List) line: 273

ZookeeperRegistry(FailbackRegistry).notify(URL, NotifyListener, List) line: 259

ZookeeperRegistry.doSubscribe(URL, NotifyListener) line: 170

ZookeeperRegistry(FailbackRegistry).subscribe(URL, NotifyListener) line: 189

RegistryDirectory.subscribe(URL) line: 134

RegistryProtocol.doRefer(Cluster, Registry, Class, URL) line: 271

RegistryProtocol.refer(Class, URL) line: 254

ProtocolListenerWrapper.refer(Class, URL) line: 63

ProtocolFilterWrapper.refer(Class, URL) line: 60

Protocol$Adpative.refer(Class, URL) line: not available

ReferenceBean(ReferenceConfig).createProxy() line: 394

ReferenceBean(ReferenceConfig).init() line: 303

ReferenceBean(ReferenceConfig).get() line: 138

ReferenceBean.getObject() line: 65

DefaultListableBeanFactory(FactoryBeanRegistrySupport).doGetObjectFromFactoryBean(FactoryBean, String, boolean) line: 142

整体来说: 先由注册中心的协议处理器处理注册中心的地址,找到所有provider的地址,创建所有invoker,然后再由invoker在真正调用时发起调用。

注册中心的这个也抽象一种协议,由注册中心结合提供者的协议推导出提供者的协议地址,也就是目标端的地址与端口得知了。

每一个接口在zookeeper上都有节点,节点下面是provider,再下面是所有provider的具体地址。

2. netty client的基本步骤

创建channelPipelineFactory,并在这个factory中返回加工好的ChannelPipeline,加工过程包括加入编解码器,连接事件处理组成的netty handler实现

(包括连接建立,断开,请求写出去,)

writeRequested(netty的)-->调用编码器(编码的这个对象中包括了 需要调用的目标接口名 方法名等信息)

(继承SimpleChannelHandler重写逻辑,可以定制channel的读取与写出逻辑)

3. 在使用zookeeper作为注册中心时,如果有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);

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

如果在发服务时,provider停掉了,那么此时会抛出异常,并在FailoverClusterInvoker doInvoke中捕获,

FailoverClusterInvoker支持调用失败时重试(可配置),此时达到再次重试的目的。

5. 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);
}

6. 对于多个provider,dubbo默认在哪里选择了一个invoker进行调用的

com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.select(LoadBalance, Invocation, List<Invoker>, List<Invoker>)。

com.alibaba.dubbo.rpc.filter.EchoFilter@1fd14d74

com.alibaba.dubbo.rpc.filter.ClassLoaderFilter@563e4951

com.alibaba.dubbo.rpc.filter.GenericFilter@4066c471

com.alibaba.dubbo.rpc.filter.ContextFilter@2b175c00

com.alibaba.dubbo.rpc.protocol.dubbo.filter.TraceFilter@3eb81efb

com.alibaba.dubbo.rpc.filter.TimeoutFilter@1ae8bcbc

com.alibaba.dubbo.monitor.support.MonitorFilter@6cdba6dc

com.alibaba.dubbo.rpc.filter.ExceptionFilter@2609b277

最新文章

  1. 多线程之任务: Task 基础, 多任务并行执行, 并行运算(Parallel)
  2. 【工匠大道】markdown使用技巧
  3. boost的编译
  4. WebDAV 配置及相关工具
  5. dubbo 教程
  6. Loadrunner之API测试
  7. [论文笔记] 一种Java遗留系统服务化切分和封装方法 (计算机学报, 2009)
  8. iOS开发小技巧--父子控制器练习中get到的技能,控制核心动画的范围
  9. Bootstrap:弹出框和提示框效果以及代码展示
  10. 关于Cygwin的x-Server的自动运行以及相关脚本修改
  11. SQL Server 添加登录账户配置权限
  12. Microsoft Dynamics CRM 2011 相关-摘自网络
  13. 使用国人的koala来重新预编译BOOTSTRAP的LESS文件
  14. HDU4757--Tree 可持久化trie + LCA
  15. IIS7中配置脚本错误解决方案
  16. Js闭包与循环
  17. IOS网络请求之NSURLSession使用
  18. DES加密解密与AES加密解密
  19. jsp页面集成xhEditor文本编辑器
  20. vi 命令

热门文章

  1. 关于window.event.returnValue=false的用处
  2. Date 对象 时间格式注意事项
  3. IOS使用固定定位遇到的问题
  4. Beginning Python Chapter 1 Notes
  5. 配置文件无法修改(以修改my-default.ini为例)
  6. POJ 1185 炮兵阵地 (状压DP,轮廓线DP)
  7. Cocos2d-x——导入Cocostudio资源
  8. 使用HelpProvide组件调用帮助文件
  9. git使用stash存储相关操作
  10. char与varchar的区别与联系