1. 路由的作用
服务路由的作用就是可以限制消费者可以调用哪些服务提供者;
路由的规则:
[服务消费者匹配条件] => [服务提供者匹配条件]
如果消费者条件为空,则表示对所有消费方应用; => host != 10.20.153.11
如果服务提供者条件为空,表示禁止访问; host = 10.20.153.10 =>
=号,表示匹配,比如:host = 10.20.153.10
!=号,表示不匹配,比如:host != 10.20.153.10
参数值,号分隔多个值,比如:host != 10.20.153.10,10.20.153.11
号结尾表示通配符:host != 10.20.
服务调用信息,如:method, argument 等,暂不支持参数路由
URL 本身的字段,如:protocol, host, port 等
以及 URL 上的所有参数,如:application, organization 等
示例:
- => host != 172.22.3.91 所有消费方都不访问该地址;
- method = find*,list*,get*,is* => host = 172.22.3.94,172.22.3.95,172.22.3.96
方法=find*,list*,get*,is*开头的都访问host=172.22.3.94,172.22.3.95,172.22.3.96 - method != find*,list*,get*,is* => host = 172.22.3.97,172.22.3.98
2. 路由源码
它的源码入口从com.alibaba.dubbo.registry.integration.RegistryDirectory#route
服务目录这里开始,
private List<Invoker<T>> route(List<Invoker<T>> invokers, String method) {
Invocation invocation = new RpcInvocation(method, new Class<?>[0], new Object[0]);
List<Router> routers = getRouters();
if (routers != null) {
for (Router router : routers) {
// If router's url not null and is not route by runtime,we filter invokers here
if (router.getUrl() != null && !router.getUrl().getParameter(Constants.RUNTIME_KEY, false)) {
invokers = router.route(invokers, getConsumerUrl(), invocation);
}
}
}
return invokers;
}
从这里也可以看出,dubbo的路由是可以方法级别配置的;
com.alibaba.dubbo.rpc.cluster.router.condition.ConditionRouter#route
@Override
public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation)
throws RpcException {
if (invokers == null || invokers.isEmpty()) {
return invokers;
}
try {
// 先对服务消费者条件进行匹配,如果匹配失败,表明服务消费者 url 不符合匹配规则,
// 无需进行后续匹配,直接返回 Invoker 列表即可。比如下面的规则:
// host = 10.20.153.10 => host = 10.0.0.10
// 这条路由规则希望 IP 为 10.20.153.10 的服务消费者调用 IP 为 10.0.0.10 机器上的服务。
// 当消费者 ip 为 10.20.153.11 时,matchWhen 返回 false,表明当前这条路由规则不适用于
// 当前的服务消费者,此时无需再进行后续匹配,直接返回即可。
if (!matchWhen(url, invocation)) {
return invokers;
}
List<Invoker<T>> result = new ArrayList<Invoker<T>>();
if (thenCondition == null) {
logger.warn("The current consumer in the service blacklist. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey());
return result;
}
for (Invoker<T> invoker : invokers) {
// 这里可以简单的把 Invoker 理解为服务提供者,现在使用服务提供者匹配规则对
// 若匹配成功,表明当前 Invoker 符合服务提供者匹配规则。
if (matchThen(invoker.getUrl(), url)) {
result.add(invoker);
}
}
if (!result.isEmpty()) {
return result;
} else if (force) {
logger.warn("The route result is empty and force execute. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey() + ", router: " + url.getParameterAndDecoded(Constants.RULE_KEY));
return result;
}
} catch (Throwable t) {
logger.error("Failed to execute condition router rule: " + getUrl() + ", invokers: " + invokers + ", cause: " + t.getMessage(), t);
}
return invokers;
}