背景
我们有个业务的项目,已做了微服务拆分,使用dubbo的rpc框架。有多位开发同事一起参与开发,但可能每个同事在同一时刻负责的版本不一样,例如有2位同事负责开发版本1,有另外2位同事负责开发版本2。某一天,一位同学向我吐槽,在本地开发调试过,自己开发的版本1的web经常调用到另外一为同事开发版本2的app,不能得到自己想要的结果。又不想逐个修改dubbo的@reference注解中url参数或者在jvm参数中增加类似-Dcom.test.testService=dubbo://localhost:20880等配置。
方案
1.实现自定义cluster,查询本地ip和注册zk的dubbo接口配置
2.若配置中存在与本地ip相同,则选取ip为本地ip的Invoker发起远程调用
3.若不存在,则交付默认cluster执行
4.配合apollo配置中心,本地开发环境开启自定义cluster,生产环境默认不开启
具体实现
1.新建DevCluster类继承Cluster
2.在resource文件夹下新建META-INF/dubbo/org.apache.dubbo.rpc.cluster.Cluster文件,文件内容:
dev=com.test.common.dubbo.DevCluster
3.开发环境,apollo开启配置:dubbo.consumer.cluster = dev(生产环境不增加此配置,使用默认的)
@Slf4j
public class DevCluster implements Cluster {
public final static String NAME = "dev";
@Override
public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
return new AbstractClusterInvoker<T>(directory) {
public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
// 1.检查是否有可用invoker
checkInvokers(invokers, invocation);
// 2.查询本地IP和注册zk的Dubbo使用IP
String ip = NetUtils.getLocalHost();
List<String> registerHosts = invokers.stream().map(i->i.getUrl().getHost()).collect(Collectors.toList());
// 3.注册IP为空,或者本地IP不在zk测试IP,则交由原cluster处理
if (CollectionUtils.isEmpty(registerHosts) || !registerHosts.contains(ip)){
FailoverClusterInvoker failoverClusterInvoker = new FailoverClusterInvoker(directory);
return failoverClusterInvoker.doInvoke(invocation,invokers,loadbalance);
}
Invoker<T> invoked = invokers.stream().filter(invoker -> invoker.getUrl().getHost().equals(ip)).findFirst()
.orElseThrow(() -> new RpcException("Failed to invoke the method "));
// 4.使用选取的Invoker发起远程调用,失败则抛出异常
try {
return invoked.invoke(invocation);
} catch (Throwable e) {
log.error("");
throw (RpcException) e;
}
}
};
}
}
网友评论