因为项目部署分需要灰度发布,涉及到公用依赖需要根据版本号来路由到不同机器。
使用了dubbo的keeper项目作为后台管理来新增路由规则,翻看dubbo源码,
发现dubbo使用了代理,代理会做的一件事就是使用路由规则,
//AbstractDirectory 类
public List<Invoker<T>> list(Invocation invocation) throws RpcException {
if (this.destroyed) {
throw new RpcException("Directory already destroyed .url: " + this.getUrl());
} else {
List<Invoker<T>> invokers = this.doList(invocation);
List<Router> localRouters = this.routers;
if (localRouters != null && !localRouters.isEmpty()) {
Iterator var4 = localRouters.iterator();
while(var4.hasNext()) {
Router router = (Router)var4.next();
try {
//这行代码可以看出,如果需要每次调用都使用规则的话,需要在提供服务那边加上
//@Service(parameters = {"runtime", "true"}) 这个注解
if (router.getUrl() == null || router.getUrl().getParameter("runtime", false)) {
invokers = router.route(invokers, this.getConsumerUrl(), invocation);
}
} catch (Throwable var7) {
logger.error("Failed to execute router: " + this.getUrl() + ", cause: " + var7.getMessage(), var7);
}
}
}
return invokers;
}
}
目前存在消费者A调用服务B,消费者C调用服务D。
现在存在的问题是,如果服务B挂了,则根据dubbo的服务降级等默认策略,此时消费者A会调用服务D,此时就
没有起到路由的作用。
继续看源码:
//ConditionRouter 类
public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
if (invokers != null && !invokers.isEmpty()) {
try {
if (!this.matchWhen(url, invocation)) {
return invokers;
}
List<Invoker<T>> result = new ArrayList();
if (this.thenCondition == null) {
logger.warn("The current consumer in the service blacklist. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey());
return result;
}
Iterator var5 = invokers.iterator();
while(var5.hasNext()) {
Invoker<T> invoker = (Invoker)var5.next();
if (this.matchThen(invoker.getUrl(), url)) {
result.add(invoker);
}
}
if (!result.isEmpty()) {
return result;
}
//此时如果force = true的话,而此时result是为空的,可以发现上次调用router的地方会抛出异常,导致本次调用失败,然后可以通过报警,告知服务挂了,而不是调用被隔离的服务D
if (this.force) {
logger.warn("The route result is empty and force execute. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey() + ", router: " + url.getParameterAndDecoded("rule"));
return result;
}
} catch (Throwable var7) {
logger.error("Failed to execute condition router rule: " + this.getUrl() + ", invokers: " + invokers + ", cause: " + var7.getMessage(), var7);
}
return invokers;
} else {
return invokers;
}
}
但是发现在keeper的配置地方没有配置force=true的地方,因此只能侵入代码,在创建路由规则的时候,令force=true