负载均衡

目前主流的负载方案分为以下两种:

集中式负载均衡:在消费者和服务提供方中间使用独立的代理方式进行负载,有硬件的(比如 F5),也有软件的(比如 Nginx)。
也就是服务器端负载均衡,请求到达后端服务器之后由这些负载均衡器根据⼀定的算法将请求路由到⽬标服务器处理。

客户端负载均衡,根据自己的请求情况做负载,Ribbon 就属于客户端自己做负载。服务消费者客户端会有⼀个服务器地址列表,调⽤⽅在请求前通过⼀定的负载均衡算法选择⼀个服务器进⾏访问,负载均衡算法的执⾏是在请求客户端进⾏。

一、SpringCloud Ribbon简介

Spring Cloud Ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡工具,它基于 Netflix Ribbon 实现。
通过 Spring Cloud 的封装,可以让我们轻松地将面向服务的 REST 模版请求自动转换成客户端负载均衡的服务调用。

二、Ribbon在Spring Cloud中的使用

1.使用 RestTemplate 与整合 Ribbon

Spring 提供了一种简单便捷的模板类来进行 API 的调用,那就是 RestTemplate。(在SpringCloud入门 —— Eureka服务注册与发现已经使用过restTemplate)

新建一个同之前一样的服务(端口不同),作为服务提供者(可看做是一个“小集群”)

spring boot 负载均衡 负载均衡springcloud_客户端


测试代码:

@Value("${server.port}")
private String port;

@GetMapping("/ribbonTest")
public String ribbonTest() {
      return "我是服务提供者 -- 我的端口是:" + port;

服务消费者

在服务消费者中已经引入了eureka-client依赖,这里就不用加入其他的依赖了,因为 Eureka 中已经引用了 Ribbon。

RestTemplate配置,加上LoadBalanced注解实现负载均衡

package com.local.springboot.client.clientcustomer.config;

import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder.build();
    }
}

测试代码:

/**
 * 访问服务
 */
private static final String REST_URL_PREFIX = "http://CLIENT-PROVIDER-SERVER";
/**
 * restTemplate负载均衡测试
 *
 * @return
 */
@RequestMapping("/restTemplate/testRibbon")
public String testRibbon2() {
    // 使用restTemplate发起请求
    String result = restTemplate.getForEntity(REST_URL_PREFIX + "/api/ribbonTest", String.class).getBody();
    return result;
}

启动服务注册中心,访问Eureka(localhost:8080),三个服务已经注册

spring boot 负载均衡 负载均衡springcloud_Server_02

测试接口,消费者调用http://localhost:8082/restTemplate/testRibbon,Ribbon会从注册中心的服务列表拉取实例集合进行负载均衡调用背后的服务提供者,如下图所示:

spring boot 负载均衡 负载均衡springcloud_Server_03

2.使用 Feign客户端

Feign客户端实际是对Ribbon进行了一个封装;spring-cloud-starter-feign 里面已经包含了 spring-cloud-starter-ribbon

不熟悉Feign调用,请戳SpringCloud入门 —— Feign服务调用

测试代码:
服务消费者

/**
 * feign负载均衡测试
 *
 * @return
 */
@RequestMapping("/feign/testRibbon")
public String testRibbon1() {
    return myFeign.ribbonTest();
}
@FeignClient(value = "client-provider-server", path = "/api", fallback = MyFeignFallback.class
        , fallbackFactory = MyFeignFallbackFactory.class)
public interface MyFeign {
    @GetMapping("/ribbonTest")
    String ribbonTest();
}

效果如下:

spring boot 负载均衡 负载均衡springcloud_Server_04

三、Ribbon负载均衡策略

Ribbon 作为一款客户端负载均衡框架,默认的负载策略是轮询,同时也提供了很多其他的策略,能够让用户根据自身的业务需求进行选择。

负载均衡策略

描述

RoundRobinRule

轮询选择,轮询 index,选择 index 对应位置的 Server。

BestAvailabl

选择一个最小的并发请求的 Server,逐个考察 Server,如果 Server 被标记为错误,则跳过,然后再选择 ActiveRequestCount 中最小的 Server。

AvailabilityFilteringRule

过滤掉那些一直连接失败的且被标记为 circuit tripped 的后端 Server,并过滤掉那些高并发的后端 Server 或者使用一个 AvailabilityPredicate 来包含过滤 Server 的逻辑。其实就是检查 Status 里记录的各个 Server 的运行状态。

ZoneAvoidanceRule

使用 ZoneAvoidancePredicate 和 AvailabilityPredicate 来判断是否选择某个 Server,前一个判断判定一个 Zone 的运行性能是否可用,剔除不可用的 Zone(的所有 Server),AvailabilityPredicate 用于过滤掉连接数过多的 Server。

RandomRule

随机选择一个 Server。

RetryRule

对选定的负载均衡策略机上重试机制,也就是说当选定了某个策略进行请求负载时在一个配置时间段内若选择 Server 不成功,则一直尝试使用 subRule 的方式选择一个可用的 Server。

ResponseTimeWeightedRule

作用同 WeightedResponseTimeRule,ResponseTime-Weighted Rule 后来改名为 WeightedResponseTimeRule。

WeightedResponseTimeRule

根据响应时间分配一个 Weight(权重),响应时间越长,Weight 越小,被选中的可能性越低。

代码配置Ribbon

@Configuration
public class RibbonConfig {

    @Bean
    public IRule ribbonRule(){
        return new RandomRule(); //分配策略:随机选择一个server
//        return new BestAvailableRule(); //分配策略:选择一个最小的并发请求的server,逐个考察Server,如果Server被tripped了,则忽略
//        return new RoundRobinRule(); //分配策略:轮询选择,轮询index,选择index对应位置的server
//        return new WeightedResponseTimeRule(); //分配策略:根据响应时间分配一个weight(权重),响应时间越长,weight越小,被选中的可能性越低
//        return new ZoneAvoidanceRule(); //分配策略:复合判断server所在区域的性能和server的可用性选择server
//        return new RetryRule(); //分配策略:对选定的负载均衡策略机上重试机制,在一个配置时间段内当选择server不成功,则一直尝试使用subRule的方式选择一个可用的server
    }

    @Bean
    public IPing ribbonPing() {
        return new PingUrl();
    }

    @Bean
    public ServerListSubsetFilter serverListFilter() {
        ServerListSubsetFilter filter = new ServerListSubsetFilter();
        return filter;
    }
}

启动类上加上@RibbonClient(name = "client-provider-server", configuration = RibbonConfig.class),关联 RibbonConfig ,用 name 来指定调用的服务名称。

配置文件配置 Ribbon

<clientName>.ribbon.NFLoadBalancerClassName: Should implement ILoadBalancer(负载均衡器操作接口)
<clientName>.ribbon.NFLoadBalancerRuleClassName: Should implement IRule(负载均衡算法)
<clientName>.ribbon.NFLoadBalancerPingClassName: Should implement IPing(服务可用性检查)
<clientName>.ribbon.NIWSServerListClassName: Should implement ServerList(服务列表获取)
<clientName>.ribbon.NIWSServerListFilterClassName: Should implement ServerList­Filter(服务列表的过滤)