Ribbon是Netflix公司开源的一个负载均衡的项目,它属于上述的第二种,是一个客户端负载均衡器,运行在客户端上。Spring Cloud Ribbon是在Netflix Ribbon的基础上作了进一步的封装,使它更加适合与微服本文主要如下俩个方便分析Ribbon的原理算法
了解Spring boot的自动化装配的同窗都知道,在Spring boot启动过程当中会加载在/META-INF/spring.factories文件下定义的配置类,而和Ribbon相关的主要配置类为LoadBalancerAutoConfiguration,在以下文件下spring
查看LoadBalancerAutoConfiguration的源码可知,在其内部定义了一个LoadBalancerInterceptor的拦截器,用于实现对客户端发起请求时进行拦截,以实现客户端负载均衡。服务器
LoadBalancerInterceptor源码以下并发
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor { private LoadBalancerClient loadBalancer; private LoadBalancerRequestFactory requestFactory; public LoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) { this.loadBalancer = loadBalancer; this.requestFactory = requestFactory; } public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) { // for backwards compatibility this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer)); } @Override public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException { final URI originalUri = request.getURI(); String serviceName = originalUri.getHost(); Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri); return this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution)); } }
从源码中能够看出,LoadBalancerInterceptor主要是将负载均衡的功能委托给负载均衡客户端LoadBalancerClient。负载均衡
在看一下RibbonLoadBalancerClient的excute方法dom
public <T> T execute(String serviceId, LoadBalancerRequest<T> request, Object hint) throws IOException { ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId); Server server = this.getServer(loadBalancer, hint); if(server == null) { throw new IllegalStateException("No instances available for " + serviceId); } else { RibbonLoadBalancerClient.RibbonServer ribbonServer = new RibbonLoadBalancerClient.RibbonServer(serviceId, server, this.isSecure(server, serviceId), this.serverIntrospector(serviceId).getMetadata(server)); return this.execute(serviceId, (ServiceInstance)ribbonServer, (LoadBalancerRequest)request); } }
从代码中能够看出LoadBalancerClient主要是经过负载均衡器ILoadBalancer查出对应的server而后执行。而getServer就是实现负载均衡的地方。ide
咱们再看一下getServer的实现函数
protected Server getServer(ILoadBalancer loadBalancer, Object hint) { return loadBalancer == null?null:loadBalancer.chooseServer(hint != null?hint:"default"); }
发现是经过ILoadBalancer的chooseServer方法实现的,再看一下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; } } }
咱们发现是经过rule.choose方法实现的,而rule实际上是IRule(负载均衡策略接口)。this
总结Ribbon的负载均衡实现,主要是经过LoadBalancerInterceptor拦截器在请求时进行拦截实现负载均衡,而LoadBalancerInterceptor将负载均衡委托给了LoadBalancerClient,而LoadBalancerClient具体交给了ILoadBalancer来处理,ILoadBalancer是根据IRule的策略进行负载均衡。
Ribbon主要包括如下核心接口
接口 | 描述 | 默认实现 |
ILoadBalancer | 负载均衡选择服务的核心方法接口 | ZoneAwareLoadBalancer |
IRule | 负载均衡策略接口 | ZoneAvoidanceRule |
IPing | 按期检查服务可用性的接口 | DummyPing |
ServerList<Server> | 获取服务列表接口 | ConfigurationBaseServerList |
ServerListUpdate | 更新服务列表接口 | PollingServerListUpdate |
ServerListFilter<Server> | 过滤服务列表接口 | ZonePerferenceServerListFilter |
IClientConfig | ribbon中管理配置接口 | DefaultClientConfigImpl |
下面咱们在介绍一下Ribbon的核心接口ILoadBalancer和IRule
ILoadBalancer的继承关系以下
ILoadBalancer:定义了负载均衡器的主要方法
AbstractLoadBalancer:实现 ILoadBalancer 接口,提供一些默认实现
BaseLoadBalancer:类是Ribbon负载均衡器的基础实现类,在该类中定义不少关于均衡负载器相关的基础内容
DynamicServerListLoadBalancer:它是对基础负载均衡器的扩展。在该负载均衡器中,实现了服务实例清单的在运行期的动态更新能力;同时,它还具有了对服务实例清单的过滤功能。
ZoneAwareLoadBalancer:负载均衡器是对DynamicServerListLoadBalancer的扩展。在DynamicServerListLoadBalancer中,咱们能够看到它并无重写选择具体服务实例的chooseServer函数,因此它依然会采用在BaseLoadBalancer中实现的算法,使用RoundRobinRule规则,以线性轮询的方式来选择调用的服务实例,该算法实现简单并无区域(Zone)的概念,因此它会把全部实例视为一个Zone下的节点来看待,这样就会周期性的产生跨区域(Zone)访问的状况,因为跨区域会产生更高的延迟,这些实例主要以防止区域性故障实现高可用为目的而不能做为常规访问的实例,因此在多区域部署的状况下会有必定的性能问题,而该负载均衡器则能够避免这样的问题。
ILoadBalancer是根据IRule定义的负载均衡策略来进行选择服务的,主要有如下7中负载均衡策略
Ribbon中的7中负载均衡算法:
RoundRobinRule:轮询;
RandomRule:随机;
AvailabilityFilteringRule:会先过滤掉因为屡次访问故障而处于断路器状态的服务,还有并发的链接数量超过阈值的服务,而后对剩余的服务列表按照轮询策略进行访问;
WeightedResponseTimeRule:根据平均响应时间计算全部服务的权重,响应时间越快的服务权重越大被选中的几率越大。刚启动时若是统计信息不足,则使用RoundRobinRule(轮询)策略,等统计信息足够,会切换到WeightedResponseTimeRule;
RetryRule:先按照RoundRobinRule(轮询)策略获取服务,若是获取服务失败则在指定时间内进行重试,获取可用的服务;
BestAvailableRule:会先过滤掉因为屡次访问故障而处于断路器跳闸状态的服务,而后选择一个并发量最小的服务;
ZoneAvoidanceRule:复合判断Server所在区域的性能和Server的可用性选择服务器;