前言
当消费者启动或者注册中心的providers节点数据发生变化时,都会重新构建消费端内存中的本地服务列表。
dubbo还提供了路由规则,决定一次 dubbo 服务调用的目标服务器,分为条件路由规则和脚本路由规则,并且支持可扩展。
原理
在构建服务列表中方法与invokers的映射关系:methodInvokerMap时,最终会利用Router对象,对每一个方法对应的Invokers进行一次路由过滤。
route使用规则:
-
API写入路由规则
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181")); registry.register(URL.valueOf("route://0.0.0.0/com.foo.BarService?category=routers&dynamic=false&rule=" + URL.encode("host = 10.20.153.10 => host = 10.20.153.11")));
具体route协议配置:
dubbo官网-路由规则 -
dubbo-admin界面操作
示例 : 消费端调用UserService的getUser方法,调用ip为192.168.1.1的主机,不调用ip为192.168.1.11的主机
image
源码
仍然是在RegistryDirectory类中,RegistryDirectory实现NotifyListener接口,并在消费端启动注册consumer协议之后,作为监听器注册到zk,用于监听configurators,providers,routes节点。注册监听器后会获取到这三个节点的children手动调用RegistryDirectory的notify方法调用监听器逻辑,用于服务列表的初始化。
后续configurators,providers,routes节点发生变化,zk同样会调用监听器RegistryDirectory的notify方法,并传入最新的children,以通知消费端更新服务列表。
dubbo-admin 添加路由规则
触发监听器的notify方法
notify(url)
-
category为route的url放到routerUrls这个list中
image -
Router对象集合的获取
zk /dubbo/${servicePath}/routes下的每一个route协议url都会对应一个Router对象
imageimage- ConditionRouter :条件路由规则
- ScriptRouter : js脚本路由
- TagRouter : 标签路由规则
- MockInvokersSelector
调用toRouters(routerUrls)创建route对象集合,
image利用SPI工厂根据url的protocol获取对应的路由规则类实例,由于这里是condition协议,所以获取到的ConditionRouter类的实例
image中途还加了MockInvokersSelector,TagRouter两种路由规则,并赋值给成员变量routers
image 过滤方法对应的invoker列表
获取到路由规则后,走刷新服务列表
过滤方法对应的invoker列表
初步建立方法对应invoker的映射关系
这部由于传入的方法为null,所以会原样返回invokers
,并建立 *和服务列表的映射
最后对每一个方法的invokers进行路由
ConditionRouter.route 过滤invokers
ConditionRouter类介绍
有两个成员变量存取变量
// 匹配方法的表达式
Map<String, MatchPair> whenCondition;
// 方法匹配成功后的条件匹配表达式
Map<String, MatchPair> thenCondition;
对应着dubbo-admin的以下配置
ip黑名单 192.168.100.72
作用方法 com.lb.dubbo_api.service.UserService.getUser()
route方法
传入的invocation的mehtodName='getUser',路由之前有两个invoker对象,分别是以下两个服务提供者
dubbo://192.168.31.211:20882/com.lb.dubbo_api.service.UserService?anyhost=true&application=dubbo-p&bean.name=ServiceBean:com.lb.dubbo_api.service.UserService&dubbo=2.0.2&generic=false&interface=com.lb.dubbo_api.service.UserService&methods=getUser&pid=2156&side=provider×tamp=1626619321787
dubbo://192.168.100.72:20882/com.lb.dubbo_api.service.UserService?anyhost=true&application=dubbo-p&bean.name=ServiceBean:com.lb.dubbo_api.service.UserService&dubbo=2.0.2&generic=false&interface=com.lb.dubbo_api.service.UserService&methods=getUser&pid=10228&side=provider×tamp=1626685187324
-
matchWhen(url,invocation )先判断方法是否匹配,如果不配置,直接返回原Invokes,就是不做任何过滤
imageimage从invocation拿到methodName和whenCondition进行比较,如果相同就返回true
image -
matchThen 判断每一个invoker是否满足thenCondition
image根据thenCondition的key取出具体要过滤的内容,再与传入的url里的相应的配置进行比较,匹配不成功就返回false,不加入到外面的结果集里
image最后就只剩下192.168.31.211这个服务了
image最终put到newMethodInvokerMap
image所以到最后,getUser方法能调到的服务提供方经过路 由规则,会剔除掉配置的ip黑名单里的那台机器,只能 调到192.168.31.211这台机器