dubbo系列之集群容错-router路由规则

dubbo系列之集群容错-router路由规则

简介

ScriptRouter:脚本路由

MockInvokersSelector :默认路由

ConditionRouter:条件路由,后台管理的路由配置都是条件路由。

本篇主要就是介绍ConditionRouter。

灰度发布

灰度发布是指在黑与白之间,能够平滑过渡的一种发布方式。AB test就是一种灰度发布方式,让一部分用户继续用A,一部分用户开始用B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。

路由中灰度发布的例子

第一步:启动provider 192.168.56.2 192.168.56.3

provider启动

第二步:切断192.168.48.32访问流量(在dubbo Admin–路由规则里设置),然后启动。

第三步:192.168.48.32发布成功后,恢复 192.168.48.32的流量,

第四步:切断192.168.100.38,继续发布 192.168.100.38(操作同上)

这样整个灰度发布的过程就结束了。。。

ok,看完上面的例子,我们可能会想问题,比如启动路由规则,触发了哪些动作?

那就带着问题来看源码吧。

源码构成

上面已经提到了ConditionRouter是条件路由,后台管理的路由配置都是条件路由。

点击路由规则里面的启用按钮时,会触发RegistryDirectort类里面的notify方法

RegistryDirectort类

notify()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public synchronized void notify(List<URL> urls) {
//......
// routers
if (routerUrls != null && routerUrls.size() > 0) {
List<Router> routers = toRouters(routerUrls);
if (routers != null) { // null - do nothing
setRouters(routers);
}
}
List<Configurator> localConfigurators = this.configurators; // local reference
// 合并override参数
this.overrideDirectoryUrl = directoryUrl;
if (localConfigurators != null && localConfigurators.size() > 0) {
for (Configurator configurator : localConfigurators) {
this.overrideDirectoryUrl = configurator.configure(overrideDirectoryUrl);
}
}
// providers
refreshInvoker(invokerUrls);
}
toRouter()——加入路由
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private List<Router> toRouters(List<URL> urls) {
List<Router> routers = new ArrayList<Router>();
if (urls == null || urls.size() < 1) {
return routers;
}
if (urls != null && urls.size() > 0) {
for (URL url : urls) {
if (Constants.EMPTY_PROTOCOL.equals(url.getProtocol())) {
continue;
}
String routerType = url.getParameter(Constants.ROUTER_KEY);
if (routerType != null && routerType.length() > 0) {
url = url.setProtocol(routerType);
}
try {
// 创建Router
Router router = routerFactory.getRouter(url);
if (!routers.contains(router))
routers.add(router);
} catch (Throwable t) {
logger.error("convert router url to router error, url: " + url, t);
}
}
}
return routers;
}

这样路由就加进来了,又是怎么过滤的呢?

1
2
3
4
5
6
private void refreshInvoker(List<URL> invokerUrls) {
// ......
Map<String, Invoker<T>> newUrlInvokerMap = toInvokers(invokerUrls);// 将URL列表转成Invoker列表
Map<String, List<Invoker<T>>> newMethodInvokerMap = toMethodInvokers(newUrlInvokerMap); // 换方法名映射Invoker列表
// ......
}
toMethodInvokers()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 将invokers列表转成与方法的映射关系
*
* @param invokersMap Invoker列表
* @return Invoker与方法的映射关系
*/
private Map<String, List<Invoker<T>>> toMethodInvokers(Map<String, Invoker<T>> invokersMap) {
// ......
newMethodInvokerMap.put(Constants.ANY_VALUE, invokersList);
if (serviceMethods != null && serviceMethods.length > 0) {
for (String method : serviceMethods) {
List<Invoker<T>> methodInvokers = newMethodInvokerMap.get(method);
if (methodInvokers == null || methodInvokers.size() == 0) {
methodInvokers = invokersList;
}
newMethodInvokerMap.put(method, route(methodInvokers, method));
}
}
// ......
}

接下来的流程用一张图来展示

路由过滤流程图

最后你筛选出来的结果,如果你禁用了192.168.56.2 那么最后的invokers就只有192.168.56.3。以上就是整个路由的过滤流程。