Ribbo介绍原文连接
1.Ribbon简介
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。
简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。
负载均衡
LB,即负载均衡(Load Balance),在微服务或分布式集群中经常用的一种应用。
负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA。
常见的负载均衡有软件Nginx,LVS,硬件 F5等。
相应的在中间件,例如:dubbo和SpringCloud中均给我们提供了负载均衡,SpringCloud的负载均衡算法可以自定义。
集中式LB
即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5, 也可以是软件,如nginx), 由该设施负责把访问请求通过某种策略转发至服务的提供方;
进程内LB
将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。
Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。
2.Ribbo架构
3.IRule的默认算法
IRule:根据特定算法中从服务器列表中选取一个要访问的服务,Ribbon默认的算法为轮询算法;
Ribbon中的7中负载均衡算法:
(1)RoundRobinRule:轮询;
(2)RandomRule:随机;
(3)AvailabilityFilteringRule:会先过滤掉由于多次访问故障而处于断路器状态的服务,还有并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问;
(4)WeightedResponseTimeRule:根据平均响应时间计算所有服务的权重,响应时间越快的服务权重越大被选中的概率越大。刚启动时如果统计信息不足,则使用RoundRobinRule(轮询)策略,等统计信息足够,会切换到WeightedResponseTimeRule;
(5)RetryRule:先按照RoundRobinRule(轮询)策略获取服务,如果获取服务失败则在指定时间内进行重试,获取可用的服务;
(6)BestAvailableRule:会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务;
(7)ZoneAvoidanceRule:复合判断Server所在区域的性能和Server的可用性选择服务器;
3.负载规则替换
3.1配置类
注意:不要被@ComponentScan扫描到
import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author 26414 */ @Configuration public class MySelfRule { @Bean public IRule myRule(){ //随机 return new RandomRule(); } }
3.2在主启动类上添加注解
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
4.轮询算法原理
4.1rest接口请求次数 % 服务器集群总数量 = 实际调用服务器下标,每次服务器重启后rest接口请求次数从1开始。
4.2手写轮询算法
4.2.1服务提供者Controller代码
@Value("${server.port}") private String serverPort; @GetMapping(value = "/payment/lb") public String getPaymentLB() { return serverPort; }
4.2.2服务消费者代码
1.接口
package com.fly.springcloud.lb; import org.springframework.cloud.client.ServiceInstance; import java.util.List; /** * @author 26414 */ public interface LoadBalancer { /** * 初始化 * @param serviceInstances 实例 * @return ServiceInstance */ ServiceInstance instances(List<ServiceInstance> serviceInstances); }
2.实现类
package com.fly.springcloud.lb; import org.springframework.cloud.client.ServiceInstance; import org.springframework.stereotype.Component; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** * @author 26414 */ @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 > 2147483647 ? 0 : current + 1; }while (!this.atomicInteger.compareAndSet(current,next)); System.out.println("next = " + next); return next; } @Override public ServiceInstance instances(List<ServiceInstance> serviceInstances) { int index = getAndIncrement() % serviceInstances.size(); return serviceInstances.get(index); } }
3.调用
@GetMapping(value = "/consumer/payment/lb") public String getPaymentLB() { List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE"); if(instances == null || instances.size() < 0){ return null; } ServiceInstance serviceInstance = loadBalancer.instances(instances); URI uri = serviceInstance.getUri(); return restTemplate.getForObject(uri + "/payment/lb",String.class); }