ribbon(负载均衡+restTemplate)

官方资料

Ribbon目前也进入维护模式

ribbon是什么

Spring Cloud Ribbon是基于Netlix Ribbon实现的一套客户端 负载均衡的工具。

简单的来说Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随即连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。

主要功能

LB(Load Balance负载均衡)

LB:简单的说就是将用户的请求平摊的分配到多个服务上,从而达到HA(高可用)

LB可分为:

  • 集中式LB:即在服务的消费方和提供方之间使用独立的LB设施可以是硬件,如F5, 也可以是软件,如nginx), 由该设施负责把访问请求通过某种策略转发至服务的提供方;
  • 进程内的LB:将L B逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。==Ribbon就属于进程内LB==,它只是一个类库, 集成于消费方进程,消费方通过它来获取到服务提供方的地址。

Ribbon核心组件IRule

IRule:根据特定算法从服务列表中选取一个要访问的服务

  • com.netflix.loadbalancer.RoundRobinRule——轮询(默认)
  • com.netflix.loadbalancer.RandomRule——随机
  • com.netflix.loadbalancer.RetryRule——先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内进行重试,获取可用的服务
  • WeightedResponseTimeRule——对RoundRobinRule的扩展,响应速度越快的实例选择权重越多大,越容易被选择
  • BestAvailableRule——会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
  • AvailabilityFilteringRule——先过滤掉故障实例,再选择并发较小的实例
  • ZoneAvoidanceRule——默认规则,复合判断server所在区域的性能和server的可用性选择服务器

替换负载算法

  • 修改cloud-consumer-order80

  • 要注意的地方:

    官方文档明确给出了警告:这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,
    否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,达不到特殊化定制的目的了。

  • 新建package——com.hzx.myrule

    image-20200324141816836

    @Configuration
    public class MySelfRule {
        @Bean
        public IRule iRule(){
            return new RandomRule();//随机
        }
    }
    
  • 在主启动类中添加@RibbonClient

    name:服务名 ,configuration:自定义配置的配置类(MySelfRule)

    @SpringBootApplication
    @EnableEurekaClient
    @RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
    public class OrderMain80 {
        public static void main(String[] args) {
            SpringApplication.run(OrderMain80.class,args);
        }
    }
    
  • 测试http://localhost/consumer/payment/get/44

轮询算法的原理

image-20200325163718073负载均衡算法: 接口第几次请求数%服务器集群总数量=实际调用服务器位置下标

自己动手写一个简单的轮询算法

模仿ribbon的轮询,

第一步:修改8001和8002Controller 加上

@GetMapping(value = "/payment/lb")
public String getPaymentLB() {
    return serverPort;
}

第二步:注释掉 80 中的ApplicationContextBean去掉注解@LoadBalanced

第三步:在80中创建LoadBalancer接口

public interface LoadBalancer {
    ServiceInstance instances(List<ServiceInstance> serviceInstances);
}

,编写MyLB类实现它

/**
 * 自定义轮询算法
 */
@Component
public class MyLB implements LoadBalancer {

    private AtomicInteger atomicInteger = new AtomicInteger(0);


    private 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);
        return next;
    }

    @Override
    public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
        //负载均衡算法: 接口第几次请求数%服务器集群总数量=实际调用服务器位置下标,每次服务重启动后接口计数从1开始。
        int index = getAndIncrement() % serviceInstances.size();

        return serviceInstances.get(index);
    }
}

第四步:在80中的controller中编写方法

@GetMapping("/consumer/payment/lb")
public String  getPaymentlb(){
    List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
    if (instances==null||instances.size()<=0){
        return null;
    }
    ServiceInstance serviceInstance =myLB.instances(instances);
    URI uri=serviceInstance.getUri();
    return getRestTemplate.getForObject(uri+"/payment/lb",String.class);
}

第五步:测试

Q.E.D.

知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议

只有不断的努力才会有更大的惊喜等着你去发现!!