首页 > 编程语言 > 详细

Spring Cloud Ribbon原理

时间:2020-03-15 00:19:46      阅读:93      评论:0      收藏:0      [点我收藏+]

Ribbon是Netflix公司开源的一个负载均衡的项目,它属于上述的第二种,是一个客户端负载均衡器,运行在客户端上。Spring Cloud Ribbon是在Netflix Ribbon的基础上做了进一步的封装,使它更加适合与微服本文主要以下俩个方便分析Ribbon的原理

  1. Ribbon的和核心工作原理
  2. Ribbon的核心接口

1.Ribbon怎么和RestTemplate整合的

了解Spring boot的自动化装配的同学都知道,在Spring boot启动过程中会加载在/META-INF/spring.factories文件下定义的配置类,而和Ribbon相关的主要配置类为LoadBalancerAutoConfiguration,在如下文件下

技术分享图片

 

 

查看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方法

    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就是实现负载均衡的地方。

我们再看一下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(负载均衡策略接口)。

总结Ribbon的负载均衡实现,主要是通过LoadBalancerInterceptor拦截器在请求时进行拦截实现负载均衡,而LoadBalancerInterceptor将负载均衡委托给了LoadBalancerClient,而LoadBalancerClient具体交给了ILoadBalancer来处理,ILoadBalancer是根据IRule的策略进行负载均衡。

2.Ribbon的核心接口

Ribbon主要包括以下核心接口

接口 描述 默认实现
ILoadBalancer 负载均衡选择服务的核心方法接口 ZoneAwareLoadBalancer
IRule 负载均衡策略接口 ZoneAvoidanceRule
IPing 定期检查服务可用性的接口 DummyPing
ServerList<Server> 获取服务列表接口 ConfigurationBaseServerList
ServerListUpdate 更新服务列表接口 PollingServerListUpdate
ServerListFilter<Server> 过滤服务列表接口 ZonePerferenceServerListFilter
IClientConfig ribbon中管理配置接口 DefaultClientConfigImpl

 

 

 

 

 

 

 

 

下面我们在介绍一下Ribbon的核心接口ILoadBalancer和IRule

2.1 ILoadBalancer 

ILoadBalancer的继承关系如下

 

技术分享图片

 

 

ILoadBalancer:定义了负载均衡器的主要方法

AbstractLoadBalancer:实现 ILoadBalancer 接口,提供一些默认实现

BaseLoadBalancer:类是Ribbon负载均衡器的基础实现类,在该类中定义很多关于均衡负载器相关的基础内容

DynamicServerListLoadBalancer:它是对基础负载均衡器的扩展。在该负载均衡器中,实现了服务实例清单的在运行期的动态更新能力;同时,它还具备了对服务实例清单的过滤功能。

ZoneAwareLoadBalancer:负载均衡器是对DynamicServerListLoadBalancer的扩展。在DynamicServerListLoadBalancer中,我们可以看到它并没有重写选择具体服务实例的chooseServer函数,所以它依然会采用在BaseLoadBalancer中实现的算法,使用RoundRobinRule规则,以线性轮询的方式来选择调用的服务实例,该算法实现简单并没有区域(Zone)的概念,所以它会把所有实例视为一个Zone下的节点来看待,这样就会周期性的产生跨区域(Zone)访问的情况,由于跨区域会产生更高的延迟,这些实例主要以防止区域性故障实现高可用为目的而不能作为常规访问的实例,所以在多区域部署的情况下会有一定的性能问题,而该负载均衡器则可以避免这样的问题。

2.2 IRule 负载均衡策略

ILoadBalancer是根据IRule定义的负载均衡策略来进行选择服务的,主要有以下7中负载均衡策略

Ribbon中的7中负载均衡算法:

RoundRobinRule:轮询;

RandomRule:随机;

AvailabilityFilteringRule:会先过滤掉由于多次访问故障而处于断路器状态的服务,还有并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问;

WeightedResponseTimeRule:根据平均响应时间计算所有服务的权重,响应时间越快的服务权重越大被选中的概率越大。刚启动时如果统计信息不足,则使用RoundRobinRule(轮询)策略,等统计信息足够,会切换到WeightedResponseTimeRule;

RetryRule:先按照RoundRobinRule(轮询)策略获取服务,如果获取服务失败则在指定时间内进行重试,获取可用的服务;

BestAvailableRule:会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务;

ZoneAvoidanceRule:复合判断Server所在区域的性能和Server的可用性选择服务器;

 

Spring Cloud Ribbon原理

原文:https://www.cnblogs.com/chensanzui/p/12495179.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!