Springcloud-服务调用负载均衡之Ribbon

文章目录

  • ribbon是什么
  • nginx和ribbon
  • 与springboot的集成
  • Ribbon7个自带的负载均衡算法
  • 替换成其他负载均衡策略IRule
  • 默认负载均衡轮训算法原理
  • 自定义负载均衡

ribbon是什么

netflix旗下的一个能提供实现负载均衡和服务调用的技术. Ribbon客户端组件提供一套完善的配置项如连接超时, 重试等. 简单地说就是在配置文件中列出Load Balancer后面的所有机器, Ribbon会自动的帮助你基于某种规则(如简单轮训, 随机连接等)去连接这些服务器, 我们能够很容易的基于ribbon实现自定义的负载均衡算法. ribbon = 负载均衡 + RestTemplate

nginx和ribbon

  • nginx服务端集中式的负载均衡, 是服务端的负载均衡, 所有调用交给nginx, 由nginx转发给服务器, 负载均衡是由服务端维护的
  • Ribbon进程内的负载均衡, 是客户端的负载均衡, 在调用微服务接口时, 在注册中心上获取注册服务列表之后缓存到JVM本地, 从而在本地实现RPC远程服务调用技术. 默认轮训方式实现负载均衡.

与springboot的集成

引入spring-cloud-starter-netflix-eureka-client包后, 这里面默认集成了ribbon, 所以一般无需再引入ribbon.

Ribbon7个自带的负载均衡算法

负载均衡算法的顶级接口是IRule

  1. 轮训算法(默认): RoundRobinRule
  2. 随机算法: RandomRule
  3. 重试算法: RetryRule 先按照轮训算法获取服务, 如果获取失败则在制定时间内重试再次获取其他可用服务.
  4. WeightedResponseTimeRule: 权重算法, 是对轮训算法的拓展, 响应越快的实例, 选择权重越大, 越容易被选择.
  5. BestAvailable: 会优先过滤掉由于多次访问故障而处于断路器跳闸状态的服务, 然后选择一个并发量最小的服务.
  6. AvailabilityFilteringRule: 先过滤掉故障服务, 再选择并发量最小的服务.
  7. ZoneAvoidanceRule: 复合判断server所在区域的性能和server的可用性选择服务器.

替换成其他负载均衡策略IRule

注意: 自定义负载均衡算法不能在@ComponentScan注解能扫描到的package下, 也可以理解为不能放到启动类所在的包下, 因为SpringbootApplication注解引用了ComponentScan注解.

  1. 自定义负载均衡配置类的Bean
@Configuration
public class RuleConfiguration {

  @Bean
  public IRule rule() {
    return new RandomRule();
  }
}
  1. 在启动类上添加注解
// name 访问的服务别名
@RibbonClient(name = "PAYMENT", configuration = RuleConfiguration.class)

默认负载均衡轮训算法原理

rest接口第几次请求数 % 集群的数量 = 实际调用集群服务节点的下标, 重启后rest接口调用次数从1开始计算. 如第一次请求, 服务端2个集群节点, 1 % 2 = 1

自定义负载均衡

  1. 客户端restTemplate去掉@LoadBalanced注解

  2. 自定义接口, 选择出集群中多个节点, 通过算法后得出需要调用的节点

package com.mine.lb;

import java.util.List;

import org.springframework.cloud.client.ServiceInstance;

public interface LoadBalancer {
  /**
   * 通过算法算出集群中多个实例, 最终需要调用哪个实例
   * @param instances
   * @return
   */
  ServiceInstance instances(List<ServiceInstance> instances);
}
  1. 添加实现类实现Loadalancer
package com.mine.lb;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import org.springframework.cloud.client.ServiceInstance;

@Component
public class MyLoadBalancer implements LoadBalancer {

  private AtomicInteger atomicInteger = new AtomicInteger(0);

/**
 * @return 第几次访问
 */
  private int getAndIncrement(){
    int current;
    int next;

    do {
      current = atomicInteger.get();
      next = current >= Integer.MAX_VALUE? 0: current + 1;
    } while (!atomicInteger.compareAndSet(current, next));

    return next;
  }

  @Override
  public ServiceInstance instances(List<ServiceInstance> instances) {
    int index = getAndIncrement() % instances.size();
    return instances.get(index);
  }

}

  1. 在controller层
    引入
@Autowired
  private RestTemplate restTemplate;

  @Autowired
  private LoadBalancer loadBalancer;

  @Autowired
  private DiscoveryClient discoveryClient;

然后方法中调用

@GetMapping("/consumer/order/get/{id}")
public CommonResult get(@PathVariable("id") Long id){
  // 参数payment是eureka上面服务名
  List<ServiceInstance> instances = discoveryClient.getInstances("payment");
  ServiceInstance instance = loadBalancer.instances(instances);
  URI uri = instance.getUri();
  return restTemplate.getForObject(uri.getPath() + "/payment/get/" + id,  CommonResult.class);
  }

你可能感兴趣的:(springcloud,spring,cloud,负载均衡,ribbon)