图解+源码讲解 Feign 如何选取指定服务
骐骥一跃,不能十步;驽马十驾,功在不舍 -- 荀子
相关文章
图解+源码讲解 Feign 如何将客户端注入到容器中图解+源码讲解动态代理获取 FeignClient 代理对象图解+源码讲解代理对象 ReflectiveFeign 分析
服务选择代码
private Observable<Server> selectServer() {
return Observable.create(new OnSubscribe<Server>() {
public void call(Subscriber<? super Server> next) {
try {
// 获取服务,根据负载均衡上下文获取服务
Server server = loadBalancerContext
.getServerFromLoadBalancer(loadBalancerURI, loadBalancerKey);
next.onNext(server);
next.onCompleted();
} catch (Exception e) {
next.onError(e);
}
}
});
}
LoadBalancerContext#getServerFromLoadBalancer
public Server getServerFromLoadBalancer( URI original,
Object loadBalancerKey) throws ClientException {
// 获取负载均衡器 DynamicServerListLoadBalancer ,里面包含着两个服务
// Servers=[192.168.60.1:9100, 192.168.60.1:9200]
// 更新注册列表的 serverListUpdater
ILoadBalancer lb = getLoadBalancer();
if (host == null) {
// Partial URI or no URI Case
// well we have to just get the right instances from lb - or we fall back
if (lb != null){
// 进行负载均衡器中的服务列表选择
Server svc = lb.chooseServer(loadBalancerKey);
服务选择
走的是 ZoneAwareLoadBalancer 的 chooseServer 方法,因为ZoneAwareLoadBalancer 实现了 DynamicServerListLoadBalancer,其实后面走的和ribbon 选择服务的列表一样
public Server chooseServer(Object key) {
if (!ENABLED.get() || getLoadBalancerStats().getAvailableZones().size() <= 1) {
logger.debug("Zone aware logic disabled or there is only one zone");
// 通过轮询算法进行服务选择
return super.chooseServer(key);
}
......
}
BaseLoadBalancer#chooseServer
调用默认的选择算法进行服务选择
public Server chooseServer(Object key) {
if (counter == null) {
counter = createCounter();
}
counter.increment();
if (rule == null) {
return null;
} else {
try {
return rule.choose(key);
} catch (Exception e) {
logger.warn("LoadBalancer [{}]: Error choosing server for key {}", name, key, e);
return null;
}
}
}
轮询算法 PredicateBasedRule#choose
public Server choose(Object key) {
// 获取负载均衡器
ILoadBalancer lb = getLoadBalancer();
// 选择服务
Optional<Server> server = getPredicate().
chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
if (server.isPresent()) {
// 如果服务存在着进行返回
return server.get();
} else {
return null;
}
}
根据轮询算法选择服务并且过滤#chooseRoundRobinAfterFiltering
通过 getEligibleServers 算法进行服务过滤,之后通过 incrementAndGetModulo 这个方法进行索引计算,之后通过 eligible.get(索引值)获取出服务实例
public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers, Object loadBalancerKey) {
// 服务过滤
List<Server> eligible = getEligibleServers(servers, loadBalancerKey);
if (eligible.size() == 0) {
return Optional.absent();
}
// 进行轮询算法进行索引计算之后选出服务
return Optional.of(eligible.get(incrementAndGetModulo(eligible.size())));
}
到这里发现其实和我前面说的一样就是ribbon的服务选择算法
if (svc == null){
// 192.168.60.1:9100
host = svc.getHost();
return svc;
}
到此我们就选择出来了我们想要的地址 192.168.60.1:9100
结果展示
注册中心显示
看出来我们通过负载均衡选择的服务就是从注册中心获取的服务实例
小结
其实说白了 feign 封装了 ribbon,利用了它的负载均衡策略,进行服务选择操作,比如用了它的负载均衡器 DynamicServerListLoadBalancer,当服务选择出来之后进行后续的地址访问,指定还有后续的地址解析方法【reconstructURIWithServer(server, request.getUri())】,最后通过 HttpUrlConnetcion 工具进行访问,进行最后的结果返回