Spring cloud的微服务,针对一个特定的服务,可能会有多个提供者,这本身对于部署以后提高系统健壮性和扩展性很有好处,但是在调试期间,会给开发者带来一定的不便。

我们发布微服务后,一般都是通过feignClient来执行调用的,也许我们的系统有十几个或者几十个微服务,相应的调用客户端也有很多,微服务之间也有各种调用关系,不可避免会出现多个微服务依赖于一个特定微服务的情况。

比如,我们发布了一个用户及授权微服务,我们的登录模块需要使用这个微服务,用户及权限管理也要使用这个微服务,很有可能登录和权限管理是两个开发者在分别维护,这样他们在调试时会分别启动各自的授权微服务,关系如图:

这样,在服务注册中心那里就会得到AuthorizationServer微服务的多个服务提供者,在调试时,因为feignClient的负载平衡通过Ribbon来实现,而Ribbon默认使用的是轮询策略(RoundRobinRule),它会轮流调用所有的可用服务,这会导致什么样的后果呢?就是调试人员A、B、C、D分别在调试过程中启动了AuthorizationServer服务,他们在调试时,只有1/4的机会会调用本机的服务,为了调试一个功能,需要重试多次才能轮到自己的调试服务环境,这确实会带来一定的问题,毕竟每个人的调试的功能不同,需要的测试数据很可能不同。为了解决这个问题,需要想办法让每次调用都只调用本机提供的服务。

那么,有办法实现这个功能吗?答案是有的,而且不太复杂;我们先讨论一下实现的思路:既然feignClient通过Ribbon找到需要的服务,那么我们就可以让Ribbon实现一种只调用本机的策略就可以了。具体一点就是,

通过接口获取到所有的可用服务获取本机的ip地址对比每一个可用服务的ip地址,如果和本机ip匹配,就是本机提供的服务了,这个服务就是我们要返回的服务。

Ribbon的规则通过继承类AbstractLoadBalancerRule来实现,我们也可以继承一下这个类,实现自己的规则类(具体实现见代码注释):

import com.netflix.client.config.IClientConfig;import com.netflix.loadbalancer.AbstractLoadBalancerRule;import com.netflix.loadbalancer.ILoadBalancer;import com.netflix.loadbalancer.Server;import java.net.InetAddress;import java.net.UnknownHostException;import java.util.List;/** * 只调用本机提供的服务 */public class CallLocalRule extends AbstractLoadBalancerRule { @Override public Server choose(Object key) { ILoadBalancer lb = getLoadBalancer(); if (lb == null) { return null; } //选中的服务 Server choose = null; //所有可用服务列表 List allList = lb.getReachableServers(); int serverCount = allList.size(); if (serverCount == 0) { return null; } //本机ip String ip = ""; try { InetAddress addi = InetAddress.getLocalHost(); //获取本机ip ip = addi.getHostAddress(); } catch (UnknownHostException e) { e.printStackTrace(); } //遍历可用服务,找到服务地址为本机ip的服务 for (Server server : allList) { String host = server.getHost().toLowerCase(); if (host.equals(ip)) { choose = server; break; } } //如果没有找到本机服务,取第一个可用服务 if (choose == null) { choose = allList.get(0); } return choose; } @Override public void initWithNiwsConfig(IClientConfig iClientConfig) { }}

写好这个规则类后,就是在系统里具体使用了,使用起来也很简单,在调用微服务的配置文件(application.yml)里设置一下即可:

AuthorizationServer: ribbon: NFLoadBalancerRuleClassName: com.ggnykj.tools.loadbalancer.CallLocalRule

其中,AuthorizationServer是微服务的名称,com.ggnykj.tools.loadbalancer.CallLocalRule是实现调用本地规则的类名称。

还有一点别忘了,就是正式发布前别忘了删除这个配置,毕竟这个只是方便调试使用的,正式发布的时候还是使用其他合适的规则吧。

查看原文 >>
相关文章