Spring Cloud Ribbon 是 Netflix Ribbon 实现的一套客户端 负载均衡工具
简单的说,Ribbon 是 Netflix 发布的开源项目,主要功能是提供 客户端的复杂均衡算法
和服务调用
。 Ribbon 客户端组件提供一系列完善的配置项如超时
、重试
等。简单的说,就是配置文件中列出 load Balancer
(简称 LB)后面所有的机器,Ribbon 会自动的帮助你基于某种规则(如简单轮询,随机链接
等)去链接这些机器。我们很容易使用 Ribbon 自定义的负载均衡算法。
Ribbon官网:https://github.com/Netflix/ribbon
停更进维
Spring Cloud Loadbalancer
简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA(高可用)
Nginx 是服务器负载均衡,客户端所有请求都会交给nginx, 然后 nginx 实现转发请求。即负载均衡是由服务端实现的。
Ribbon 本地负载均衡,在调用微服务接口的时候,会在注册中心上获取注册信息服务列表后缓存到JVM 本地,从而在本地实现RPC远程 服务调用技术。
即在服务的消费方和提供方之间使用独立的LB 设施(可以是硬件,如F5, 也可以是软件如 Nginx ), 由该设置负责把访问请求通过某种策略转发至服务的提供方
将 LB 逻辑集成到消费方,消费方从服务注册中心获取有哪些地址可用,然后自己再从这些地址中选择一个适合的服务器。
Ribbon
就属于进程内LB
,它只是一个类库,集成于消费方进程,消费方通过它阿莱获取服务提供方的地址。
Ribbon
其实就是一个软负载均衡的客户端组件,他可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例
HA (高可用)
两步
:第一步先选择 Server , 它优先选择在同一个区域呢负载较少的Server
第二步在根据用户执行的策略,在从server 取到的服务注册列表中选择一个地址。
其中 Ribbon 提供了多种策略:比如轮询
、随机
和根据响应时间加权
。
(测试使用Eureka做服务注册 ) 不需要
额外
导入依赖 ,在 spring-cloud-starter-netflix-eureka-client自带
spring-cloud-starter-ribbon
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate() ;
}
赋予RestTemplate 有负载均衡的能力 也是使用的 ribbon
IRule
: com.netflix.loadbalancer.IRule相关的负载均衡算法 , 均在 com.netflix.loadbalancer 包下
全类名 | 说明 |
---|---|
RoundRobinRule | 轮询 |
RandomRule | 随机 |
RetryRule | 先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试 ,获取可用的服务 |
WeightedResponseTimeRule | 对RoundRobinRule 的拓展,响应速度 越快的实例选择权重越大,越容易被选择 |
BestAvailableRule | 会先过滤掉由于多次访问故障而处断路器跳闸状态的服务,然后选择一个并发量最小的服务 |
AvailabilityFilteringRule | 先过滤掉故障 实例,在选择并发较小 的实例 |
ZoneAvoidanceRule | 默认规则,符合判断Server 所在区域的性能和 Server 的可用性选择服务器 |
@Configuration
public class MySelfRule {
@Bean
public IRule myRule(){
return new RandomRule() ;
}
}
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
// 访问指定服务,使用指定的负载均衡算法
public class OrderMain80 {
public static void main(String[] args){
SpringApplication.run(OrderMain80.class,args) ;
}
}
负载均衡算法:rest 接口第几次请求数 % 服务器集群总数量 = 时机调用服务器位置下标
,每次服务重启后rest 接口技术求从1开始。
List<ServiceInstance> instances = discoverClient.getInstances("PAYMENT-SERVICE");
如: List[0] instances = 127.0.0.1:8002
List[1] instances = 127.0.0.1:8001
8001 + 8002 组合为集群,他们共计2台服务器,集群总数为2 , 按照轮询算法原理:
当请求总数为1 时:1%2 = 1, 对应下标位置为1, 则获得服务地址为 127.0.0.1:8001
当请求总数为2 时:2%2 = 0, 对应下标位置为1, 则获得服务地址为 127.0.0.1:8002
当请求总数为3 时:2%2 = 1, 对应下标位置为1, 则获得服务地址为 127.0.0.1:8001
依次类推 。。。。
public interface LandBalance {
ServiceInstance instance(List<ServiceInstance> serviceInstances) ;
}
@Component
public class MyLb implements LandBalance {
// 原子类
private AtomicInteger atomicInteger = new AtomicInteger(0) ;
public 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 instance(List<ServiceInstance> serviceInstances) {
int index = getAndIncrement() % serviceInstances.size() ;
return serviceInstances.get(index) ;
}
}
restTemplate 上不能有 LoadBalance注解
)@Autowired
private LandBalance landBalance ;
@Autowired
DiscoveryClient discoveryClient ;
@GetMapping("/consumer/payment/lb")
public String getPaymentLb(){
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
if (instances == null || instances.size() <= 0 ){
return null ;
}
ServiceInstance instance = landBalance.instance(instances);
URI uri = instance.getUri();
return restTemplate.getForObject(uri+"/payment/lb",String.class) ;
}