springcloud微服务五:客户端负载均衡ribbon

基本概念理解

ribbon用在客户端,或者说消费端,被称作客户端负载均衡。
对于这个称呼,可以解析为三个部分,一个是客户端,一个是负载均衡,然后就是客户端负载均衡。
根据个人理解,所有发起请求的一端、去拿东西的一端,都可以称之为客户端或消费端。
而负载均衡,一般则是针对于至少两个以上的集群而言,重点在于均衡。从相对论的角度而言,一切都是相对的,那么也就不存在绝对的均衡,因此所谓的均衡就需要一定的标准,如何达到这个标准,则需要一定的控制,即负载均衡策略,也可以称之为规则。
对于客户端负载均衡,则可以很好的理解为,这是相对于服务端负载均衡而言。相对于服务端负载均衡而言,客户端负载均衡的好处就在于各个客户端自己实现负载均衡运算,从而降低了服务端的压力。坏处在于客户端要自己实现负载,就需要清楚服务端集群的状态,增加了客户端的复杂度以及多个客户端下可能看起来的功能冗余。

基本用法

pom.xml配置

ribbon的基本用法,实际上之前提过,首先还是一样需要创建一个springboot项目,然后配置maven的pom.xml文件

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.10.RELEASE</version>
    <relativePath/> 
</parent>
......
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
......
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Edgware.SR2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

注:由于和之前四篇隔得时间较长,且目前工作实际项目使用的版本是springboot1.5.0和springcloud-Edgware.SR2,因此这之后的代码示例也均已这两个版本为主。

properties文件配置

服务名
spring.application.name=ribbon-client
服务端口
server.port=9098
是否允许ip访问
eureka.instance.prefer-ip-address=true
指定注册中心的地址
eureka.client.serviceUrl.defaultZone=http://localhost:10010/eureka/

基本代码

配置好pom.xml和properties文件后之后,在springcloud启动类类名上方加入springboot的启动注解以及springcloud客户端注解

@EnableDiscoveryClient
@SpringBootApplication

之后,在启动类中加入 RestTemplate的初始化代码,并使用@Bean注解告知springboot管理,同时加入@LoadBalanced注解,代表使用ribbon负载均衡来管理RestTemplate,这一段代码大致如下:

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

有了上边的代码,我们在其他被spring管理的组件中就可以使用@Autowired这样的方式注入RestTemplate,一个被ribbon管理的RestTemplate,如下边所示:

@service
public interface RibbonService {
    @Autowired
    RestTemplate restTemplate;
    public String sayHello() {
        ResponseEntity responseEntity = restTemplate.getForEntity("http://client/hello", String.class);
        return responseEntity.getBody();
    }}

内置负载均衡策略

RoundRobinRule线性轮询策略
上边的简单实现,只使用了@LoadBalanced注解来开启ribbon负载均衡,那么就会使用ribbon默认的负载均衡策略,即线性轮询。
就如我们用酷狗等音乐播放器放歌一样,有很多方式,例如单曲循环、列表循环、随机播放,这里的线性轮询其实就是列表循环,放歌循环的是歌曲列表,线性轮询循环的是服务器列表,针对一系列的请求,从前到后依次访问列表中的服务器,到了最后边,就再回到开头。
虽然在多个服务端的情况下,线性轮询已经可以一定程度的实现负载均衡,大概也是实际使用率最高的一种方式,但是也有它的局限性,因此ribbon还内置了其他一些负载均衡策略供我们选择。

我们目前项目中就只使用了默认的负载均衡策略,不过也对其他策略有过一定的了解,下边几个是我个人认为可能也会用到的:
RandomRule随机选择策略
随机二字应该就不需要多做解释了;
RetryRule线性轮询重试策略
这个策略内部实际上还是用的线性轮询,与默认的线性轮询不一样的地方在于,这个策略在访问轮询到的服务有问题时,会在一定的时间内进行重试,这个时间可以通过maxRetryMillis参数进行配置。
WeightedResponseTimeRule权重响应时间策略
这个策略是对线性轮询的拓展,在线性轮询的情况下,不论服务器实例的性能如何,在一定的请求次数下都必然会被轮询到,这样一来,如果某个实例由于某些原因,响应时间远大于其他实例,就必然影响整体性能。
而WeightedResponseTimeRule则会对每个服务实例的响应时间进行一定的记录和计算,然后给每个实例一个权重值区间。
如果上边的权重值最大值小于0.001,那么之后的请求会采用线性轮询策略;如果大于0.001,那么对于每一个请求,会随机分配一个0到最大权重值之间的随机数,然后这个随机数在实力列表中哪个实例的权重区间内,就会选择哪个实例。
那么这里有一个细节,就是随机数算法中含头不含尾,也就是说在0到最大权重值之间的随机数,可以是0,却不会是最大权重值那个值。
另一个细节就是,根据这里的权重算法,平均响应时间越短的服务实例,它的权重区间就会越大,注意,是权重区间越大,而不是权重值。再明确点说,就是这个实力区间内能容纳的随机数个数更多。
因此,在生成随机数的时候,这个区间命中的概率就越大,这个实例被选择到的几率也更高,从而就使得平均响应时间短的实例更容易被选择到,就提升了系统效率。

除了上边四种,还有诸如最好可用策略BestAvailableRule等策略,就不再记录。
同时,还可以自己定义负载均衡策略,但是应该很少会被用到,因为内置的这些已经能够满足非常多的应用场景了。

那么,了解了不同的负载均衡策略之后,还需要知道的当然就是如何使用非默认的负载均衡策略了。
其实也比较简单,只需要在加一个让spring来管理的bean就好,如下边这样:

@Bean
public IRule ribbonRule() {
    // return new RandomRule();
    // return new RetryRule();
    return new WeightedResponseTimeRule();
 }

推荐文章