vlambda博客
学习文章列表

走进Ribbon负载均衡

LB,即负载均衡(Load Balance),在微服务或分布式集群中经常用的一种应用。

负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA。


常见的负载均衡有软件Nginx,LVS;硬件F5等。


相应的在中间件,例如: dubbo和SpringCloud中均给我们提供了负载均衡,SpringCloud的负载均衡算法可以自定义。


负载均衡也分为:

  • 集中式的LB:即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5,也可以是软件,如nginx),由该设施负责把访问请求通过某种策略转发至服务的提供方。


Spring Cloud Ribbon就是基于Netflix Ribbon实现的一套客户端负载均衡器

是基于RestTemplate的,它赋予了RestTemplate 负载均衡的能力。我们也很容易的自定义负载均衡的算法。


Nginx为服务端(Tomcat/应用) 做负载均衡——服务端负载均衡。


下面就来看看怎么使用Ribbon?


这里接着Eureka使用的案例来继续:

先对用户服务做一个集群,然后订单服务集成Ribbon来实现负载均衡的调用。


Ribbon的工作流程:


首先做用户服务的集群,其实就是“复制”:

1 复制user-server-3000模块,起名为user-server-3001

2 修改pom文件:<artifactId>user-server-3001</artifactId>

3 修改父模块的pom文件,添加<module>user-server-3001</module>

4 修改user-server-3001模块的配置文件中的端口为:3001和服务实例名为user-server-3001

或者

新建一个子模块,内容全部复制过来即可。记得修改端口号和服务实例id


然后在order-server服务集成Ribbon

1 导包

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId></dependency>


2 修改RestTemplate的Bean的定义

RestTemplate是 SpringMvc提供的一个基于Rest风格的http调用工具。

加一个@LoadBalanced注解:ribbon的负载均衡标签,赋予RestTemplate有负债均衡的能力。

@Bean@LoadBalancedpublic RestTemplate restTemplate(){ return new RestTemplate();}


3 修改Controller调用方式

其实就是修改url。用服务名代替了ip和端口,ribbon就会根据服务名去获取多个目标服务的ip和端口,再用某种算法来实现负载均衡。默认轮询策略。

@GetMapping("user/{id}")public User getUserById(@PathVariable("id")Long id){ String url = "http://user-server/userServer/user/"+id; return restTemplate.getForObject(url, User.class);}


以上就是ribbon的初步使用,那我们想要改变负载均衡的方式应该怎么做呢?下面先来简单看看ribbon的源码吧。

我们已经知道@LoadBalanced注解赋予RestTemplate负载均衡的能力,那它是怎么赋予的?

在RestTemplate的底层通过一个RibbonLoadBalancerClient.exec客户端工具类来实现负载均衡的,而RibbonLoadBalancerClient.exec方法中做了如下事情:


@LoadBalanced-->LoadBalancerClient接口-->RibbonLoadBalancerClient实现类的execute方法-->execute方法体里面的getLoadBalancer(服务名)方法获取ILoadBalancer负载均衡器-->execute方法体里面的getServer方法返回选定的服务-->通过BaseLoadBalancer.chooseServer方法选择服务-->chooseServer方法体中会执行this.rule.choose(key)-->此时就会选择一个IRule接口的实现类去执行这个方法(默认RoundRobinRule)-->最终调用incrementAndGetModulo方法(最终算法体)


分析了源码之后,我们就知道了Ribbon是通过服务名获取到服务列表后,然后根据一定规则来选择一个服务实例来完成调用。这个规则就叫负载均衡策略。


那这个规则其实就是通过IRule接口定义的,Ribbon自身也实现了不少规则。如下表:


内置负载均衡规则类

规则描述

RoundRobinRule

轮询。它是Ribbon默认的负载均衡规则。

AvailabilityFilteringRule

对以下两种服务器进行忽略:

(1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。

可以通过修改配置loadbalancer.<clientName>.connectionFailureCountThreshold来修改连接失败多少次之后被设置为短路状态。默认是3次。

(2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上线,可以由客户端的<clientName>.<clientConfigNameSpace>.ActiveConnectionsLimit属性进行配置。

WeightedResponseTimeRule

为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小,被选中的概率就越低。

ZoneAvoidanceRule

以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。

BestAvailableRule

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

RandomRule

随机选择一个可用的服务器。

RetryRule

先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务。


在程序中,我们可以通过配置不同IRule的实现类,选择不同负载均衡策略。当然也可以通过实现IRule接口来完成自定义规则。所以负载均衡策略可以分为内置和自定义。


当我们要改变默认算法时,直接把该内置的实现类加入容器中即可,比如这里的:随机算法的配置

@Configurationpublic class BeanConfig { @Bean @LoadBalanced  public RestTemplate restTemplate(){ return new RestTemplate(); } //配置一个随机的负载均衡的算法 @Bean public IRule randomRule(){ return new RandomRule(); }}