Spring cloud Ribbon负载均衡

  • 一、简介
  • 二、负载均衡不同方案的区别
  • 1、集中式负载均衡(服务器负载均衡)
  • 2、进程内负载均衡(客户端负载均衡)
  • 三、负载均衡策略
  • 1、轮询策略(默认)
  • 2、权重轮询策略
  • 3、随机策略
  • 4、最少并发数策略
  • 5、重试策略
  • 6、可用性敏感策略
  • 7、区域敏感性策略
  • 四、自定义负载均衡策略
  • 4.1 切换负载均衡算法
  • 4.2 自定义算法


一、简介

Ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡工具,他是基于 Netftix Ribbon 实现的。其不是独立部署,但是几乎存在于每个 Spring Cloud 微服务中,包括 Feign 提供的声明式服务调用也是基于 Ribbon 实现的。

二、负载均衡不同方案的区别

1、集中式负载均衡(服务器负载均衡)

在 consumer 和 provider 之间使用独立的负载均衡设施(可以是硬件,如 F5,也可以是软件,如nginx),由该设施负责把请求通过某种策略发送至 provider

springcloud微服务负载均衡算法有哪些 springcloud的负载均衡_负载均衡

2、进程内负载均衡(客户端负载均衡)

将负载均衡逻辑集成到 consumer ,consumer 从注册中心获取可用地址,然后选择合适的 provider。 Ribbon 属于后者,他是一个类库,集成于 consumer ,consumer 通过其获取 provider 地址

springcloud微服务负载均衡算法有哪些 springcloud的负载均衡_ide_02

三、负载均衡策略

1、轮询策略(默认)

策略对应类:RoundRubinRule

实现原理:轮询策略表示每次都顺序取下一个 provider

2、权重轮询策略

策略对应类:WeightedResponseTimeRule

实现原理:

  • 根据每个 provider 的响应时间分配权重,响应时间越长,权重越小,被选中的可能性越低
  • 原理:一开始为轮询,并开启一个计时器,每 30s 收集一次每个 provider 的平均响应时间,当信息足够时,给每个 provider 附上一个权重,并按权重随机选择 provider,高权重的 provider 会被高概率选中

3、随机策略

策略对应类:RandomRule

实现原理:从 provider 列表中随机选择一个

4、最少并发数策略

策略对应类:BestAvailableRule

实现原理:选择正在请求的并发数量最小的 provider ,除非这个 provider 熔断中

5、重试策略

策略对应类:RetryRule

实现原理:轮询策略增强版,轮询策略服务不可用时不做处理,重试策略服务不可用时会重新尝试集群中的其他节点

6、可用性敏感策略

策略对应类:AvailabilityFilteringRule

实现原理:过滤性能差的 provider

  • 第一种:过滤掉在 Eureka 中处于一直连接失败的 provider
  • 第二种:过滤掉高并发的 provider

7、区域敏感性策略

策略对应类:ZoneAvoidanceRule

实现原理:过滤性能差的 provider

  • 以一个区域为单位考察可用性,对于不可用的区域整个丢弃,从剩下的区域中选取可用 provider
  • 如果这个 ip 区域内有一个或多个实例不可达或响应变慢,都会降低该 ip 区域内其他 ip 被选中的权重

四、自定义负载均衡策略

4.1 切换负载均衡算法

  • pom
<!-- Eureka 和 OpenFeign 中均有集成-->	
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
  • application
// MySelfRule.class 不可在ComponentScant扫描包中,否则会导致所有RibbonClient都进行负载均衡
@RibbonClient(name = "cloud-payment",configuration = MySelfRule.class)  
@EnableEurekaClient
@SpringBootApplication
public class OrderApplication01 {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication01.class, args);
    }
}

springcloud微服务负载均衡算法有哪些 springcloud的负载均衡_负载均衡_03

  • MySelfRule
@Configuration
public class MySelfRule {
    @Bean // 这里是引用的轮询算法
    public IRule myRule() {
        return new RandomRule(); // 随机
    }
}



4.2 自定义算法

  • pom
<!-- Eureka 和 OpenFeign 中均有集成-->	
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
  • application
@EnableEurekaClient
@SpringBootApplication
public class OrderApplication02 {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication02.class, args);
    }
}
  • loadBancer算法
@Component // LoadBalancer 接口仅做标识
public class MyLB implements LoadBalancer {

    private AtomicInteger atomicInteger = new AtomicInteger(0);

    /**
     * 获取当前轮到的服务
     * 轮询策略
     *
     * @param serviceInstances 所有可用服务列表
     * @return 服务
     */
    @Override
    public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
        return serviceInstances.get(getAndIncrement() % serviceInstances.size());
    }

    /**
     * 获取当前请求次数
     *
     * @return next
     */
    public final int getAndIncrement() {
        int current;
        int next;
        do {
            current = this.atomicInteger.get();
            next = current >= Integer.MAX_VALUE ? 0 : current + 1;
        } while (!this.atomicInteger.compareAndSet(current, next));
        System.out.println("******************next" + next);
        return next;
    }

}

springcloud微服务负载均衡算法有哪些 springcloud的负载均衡_负载均衡_04

  • controller
@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private LoadBalancer loadBalancer;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("/lb")
    public String getLB() {
        // 获取所有可用服务
        List<ServiceInstance> serviceInstances = discoveryClient.getInstances("cloud-payment");
        if (serviceInstances == null || serviceInstances.size() <= 0) {
            return null;
        }
		
        // 使用自定义算法选择被调服务
        ServiceInstance instances = loadBalancer.instances(serviceInstances);
        URI uri = instances.getUri();
        return restTemplate.getForObject(uri + "/payment/lb", String.class);
    }
}