上一篇讲了dubbo服务调用集群容错路由负载的基本链路,之前也看过了服务引用的时候,会监听zookeeper的节点,如果zk节点有变动,会通知到:org.apache.dubbo.registry.integration.RegistryDirectory#notify
zk节点变动可能会是因为:某个服务提供者出现故障下线、路由规则配置中被过滤了(比如在Dubbo-Admin中启用了配置的某条规则)等等
之前在服务引用也大概讲过了refreshOverrideAndInvoker(providerURLs)
方法
这里我们从org.apache.dubbo.rpc.cluster.Directory
接口开始看
可以看到Directory
服务目录实现有两个,分别为 StaticDirectory
和 RegistryDirectory
,它们均是 AbstractDirectory
的子类。AbstractDirectory
实现了 Directory
接口,这个接口包含了一个重要的方法定义,即 list(Invocation)
,用于列举 Invoker。AbstractDirectory
封装了 Invoker
列举流程,具体实现由StaticDirectory
和 RegistryDirectory
进行实现,这就是模板模式。
StaticDirectory
即静态服务目录,它内部存放的 Invoker 是不会变动的。所以,理论上它和不可变 List 的功能很相似RegistryDirectory
是一种动态服务目录,实现了 NotifyListener 接口。当注册中心服务配置发生变化后,RegistryDirectory 可收到与当前服务相关的变化。收到变更通知后,RegistryDirectory 可根据配置变更信息刷新 Invoker 列表。RegistryDirectory 中有几个比较重要的逻辑,第一是 Invoker 的列举逻辑,第二是接收服务配置变更的逻辑,第三是 Invoker 列表的刷新逻辑
org.apache.dubbo.registry.integration.RegistryDirectory#doList
从路由中获取可用的Invokers。
org.apache.dubbo.registry.integration.RegistryDirectory#notify
接收zk节点变化,RegistryDirectory
实现了 NotifyListener
接口,通过这个接口获取注册中心变更通知
这里我们重点看org.apache.dubbo.registry.integration.RegistryDirectory#refreshInvoker
。
refreshInvoker
方法首先会根据入参invokerUrls
的数量和协议头判断是否禁用所有的服务,如果禁用,则将forbidden
设为 true,并销毁所有的Invoker
。若不禁用,则将 url 转成Invoker
,得到 <url, Invoker> 的映射关系:Map<String, Invoker<T>> newUrlInvokerMap
- 然后调用
routerChain.setInvokers(newInvokers)
在第一时间从注册表通知路由器链初始地址(当注册表中的地址更改时通知),在上面的doList
方法中会从路由中获取Invoker,所以doList
是读取,这里是写操作 - 然后
toMergeInvokerList
会合并invoker,首先是生成 group 到 Invoker 列表的映射关系表,若关系表中的映射关系数量大于1,表示有多组服务。此时通过集群类合并每组 Invoker,并将合并结果存储到 groupInvokers 中。之后将方法名与 groupInvokers 存到到 result 中,并返回这个结果 - 接着
this.urlInvokerMap = newUrlInvokerMap
更新为最新的urlInvokerMap - 最后是
destroyUnusedInvokers
删除无用 Invoker,通过newUrlInvokerMap
找出待删除 Invoker 对应的 url,并将 url 存入到 deleted 列表中。然后再遍历 deleted 列表,并从oldUrlInvokerMap
中移除相应的 Invoker
这就大概讲完了Directory相关的东西