第六篇:负载均衡器Ribbon

什么是Ribbon

Ribbon是Netflix公司开源的一个负载均衡的项目,是一个客户端负载均衡器,运行在客户端上。它是一个经过了云端测试的IPC库,可以很好地控制HTTP和TCP客户端的一些行为。 Feign已经默认使用了Ribbon。

 

Ribbon的工作流程

image.png

 

1:user微服务1、user微服务2、user微服务3是一个服务集群,它们都会向注册中心注册服务(它们的应用名都是USER-SERVICE)

2:注册中心记录集群元数据信息,即USER-SERVICE下有3个服务节点

3:消费者调用服务前,需要ribbon根据应用名(USER-SERVICE)获取服务列表

4:ribbon采用均衡方案,给消费者返回具体的一个节点

5:消费者获得具体的服务节点实现远程调用

Ribbon实现负载均衡属于客户端的负载均衡,因为消费者就是客户端,而Ribbon就是在客户端完成负载均衡的工作。

 

Ribbon源码分析

(一)Ribbon获取应用名

LoadBalancerAutoConfiguration是Ribbon的自动配置类,在这个配置类里面配置了一个拦截器,这就是Ribbon的入口

1

2

3

4

5

6

@Bean

public LoadBalancerInterceptor ribbonInterceptor(

      LoadBalancerClient loadBalancerClient,

      LoadBalancerRequestFactory requestFactory) {

   return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);

}

 

LoadBalancerInterceptor的intercept方法(当远程调用的时候都会被拦截器拦截)

1

2

3

4

5

6

7

8

@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, requestFactory.createRequest(request, body, execution));

}

 

(二)获取负载均衡器ZoneAwareLoadBalancer

 

1

2

3

4

5

6

7

8

9

10

11

12

@Override

public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {

   ILoadBalancer loadBalancer = getLoadBalancer(serviceId);//获取负载均衡器

   Server server = getServer(loadBalancer);

   if (server == null) {

      throw new IllegalStateException("No instances available for " + serviceId);

   }

   RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,

         serviceId), serverIntrospector(serviceId).getMetadata(server));

 

   return execute(serviceId, ribbonServer, request);

}

ILoadBalancer是一个接口,具体的实现类是ZoneAwareLoadBalancer

ZoneAwareLoadBalancer负载均衡器是在RibbonClientConfiguration中提前定义的

1

2

3

4

5

6

7

@Bean

@ConditionalOnMissingBean

public ILoadBalancer ribbonLoadBalancer(IClientConfig config, ServerList<Server> serverList, ServerListFilter<Server> serverListFilter, IRule rule, IPing ping, ServerListUpdater serverListUpdater) {

    return (ILoadBalancer)(this.propertiesFactory.isSet(ILoadBalancer.classthis.name) ? 

    (ILoadBalancer)this.propertiesFactory.get(ILoadBalancer.class, config, this.name) : 

    new ZoneAwareLoadBalancer(config, rule, ping, serverList, serverListFilter, serverListUpdater));

}

(三)获取服务列表,通过均衡器获取服务列表

ZoneAwareLoadBalancer的继承关系图如下:

image.png

 

getAllServers获取服务列表,ZoneAwareLoadBalancer没有定义getAllServers方法,但是父类BaseLoadBalancer定义了该方法

 

(四)获取具体服务,通过负载均衡器获取具体服务

ZoneAwareLoadBalancer定义了获取服务的方法,但是该方法最终调用的是父类BaseLoadBalancer  chooseServer方法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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;

        }

    }

}

 

(五):默认均衡策略ZoneAvoidanceRule,均衡器获取具体服务的时候要参考均衡策略

均衡策略的接口是IRule,具体实现类有10个:

 

image.png

 

 

IRule

这是所有负载均衡策略的父接口,里边的核心方法就是choose方法,用来选择一个服务实例。

AbstractLoadBalancerRule

AbstractLoadBalancerRule是一个抽象类,里边主要定义了一个ILoadBalancer,就是我们上文所说的负载均衡器,负载均衡器的功能我们在上文已经说的很详细了,这里就不再赘述,这里定义它的目的主要是辅助负责均衡策略选取合适的服务端实例。

RandomRule

看名字就知道,这种负载均衡策略就是随机选择一个服务实例,看源码我们知道,在RandomRule的无参构造方法中初始化了一个Random对象,然后在它重写的choose方法又调用了choose(ILoadBalancer lb, Object key)这个重载的choose方法,在这个重载的choose方法中,每次利用random对象生成一个不大于服务实例总数的随机数,并将该数作为下标所以获取一个服务实例。

RoundRobinRule

RoundRobinRule这种负载均衡策略叫做轮询负载均衡策略,也就是我们在上文所说的BaseLoadBalancer负载均衡器中默认采用的负载均衡策略。这个类的choose(ILoadBalancer lb, Object key)函数整体逻辑是这样的:开启一个计数器count,在while循环中遍历服务清单,获取清单之前先通过incrementAndGetModulo方法获取一个下标,这个下标是一个不断自增长的数先加1然后和服务清单总数取模之后获取到的(所以这个下标从来不会越界),拿着下标再去服务清单列表中取服务,每次循环计数器都会加1,如果连续10次都没有取到服务,则会报一个警告No available alive servers after 10 tries from load balancer: XXXX

RetryRule

看名字就知道这种负载均衡策略带有重试功能。首先RetryRule中又定义了一个subRule,它的实现类是RoundRobinRule,然后在RetryRule的choose(ILoadBalancer lb, Object key)方法中,每次还是采用RoundRobinRule中的choose规则来选择一个服务实例,如果选到的实例正常就返回,如果选择的服务实例为null或者已经失效,则在失效时间deadline之前不断的进行重试(重试时获取服务的策略还是RoundRobinRule中定义的策略),如果超过了deadline还是没取到则会返回一个null。

WeightedResponseTimeRule

WeightedResponseTimeRule是RoundRobinRule的一个子类,在WeightedResponseTimeRule中对RoundRobinRule的功能进行了扩展,WeightedResponseTimeRule中会根据每一个实例的运行情况来给计算出该实例的一个权重,然后在挑选实例的时候则根据权重进行挑选,这样能够实现更优的实例调用。WeightedResponseTimeRule中有一个名叫DynamicServerWeightTask的定时任务,默认情况下每隔30秒会计算一次各个服务实例的权重,权重的计算规则也很简单,如果一个服务的平均响应时间越短则权重越大,那么该服务实例被选中执行任务的概率也就越大。

ClientConfigEnabledRoundRobinRule

ClientConfigEnabledRoundRobinRule选择策略的实现很简单,内部定义了RoundRobinRule,choose方法还是采用了RoundRobinRule的choose方法,所以它的选择策略和RoundRobinRule的选择策略一致,不赘述。

BestAvailableRule

BestAvailableRule继承自ClientConfigEnabledRoundRobinRule,它在ClientConfigEnabledRoundRobinRule的基础上主要增加了根据loadBalancerStats中保存的服务实例的状态信息来过滤掉失效的服务实例的功能,然后顺便找出并发请求最小的服务实例来使用。然而loadBalancerStats有可能为null,如果loadBalancerStats为null,则BestAvailableRule将采用它的父类即ClientConfigEnabledRoundRobinRule的服务选取策略(线性轮询)。

PredicateBasedRule

PredicateBasedRule是ClientConfigEnabledRoundRobinRule的一个子类,它先通过内部定义的一个过滤器过滤出一部分服务实例清单,然后再采用线性轮询的方式从过滤出来的结果中选取一个服务实例。

ZoneAvoidanceRule(Finchley.SR1版本中默认均衡策略)

ZoneAvoidanceRule是PredicateBasedRule的一个实现类,只不过这里多一个过滤条件,ZoneAvoidanceRule中的过滤条件是以ZoneAvoidancePredicate为主过滤条件和以AvailabilityPredicate为次过滤条件组成的一个叫做CompositePredicate的组合过滤条件,过滤成功之后,继续采用线性轮询的方式从过滤结果中选择一个出来。


 

(六)自定义均衡策略

在application.properties中配置:

1

2

spring-cloud-provider.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule

#spring-cloud-provider2.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule

格式说明:应用名.ribbon.NFLoadBalancerRuleClassName=xxx


 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值