前言
看前需要先看作者的上一篇博客:
点这里->SpringCloud-Eureak服务注册中心
一、Ribbon是什么
简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。
Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。简单的说,就是在配置文件中列出
Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连
接等)去连接这些机器。我们很容易使用Ribbon实现自定义的负载均衡算法。
二、Ribbon使用
1.引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
如果已经引入了spring-cloud-starter-netflix-eureka-client 依赖则不需要再次引入Ribbon依赖,因为 eureka-client 已经包括Ribbon了
2.简单使用可以看作者上篇博客(Ribbon默认负载均衡方式为轮询方式)
点这里->SpringCloud-Eureak服务注册中心
3.替换负载均衡方式
1)创建配置类
官方文档明确给出了警告:
这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,达不到特殊化定制的目的了。
@Configuration
public class MySelfRule {
@Bean
public IRule myRule()
{
return new RandomRule();//定义为随机
}
}
2)在启动类上添加注解@RibbonClient,我这里用的是随机方式实现负载均衡
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration= MySelfRule.class)
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class,args);
}
}
三、Ribbon负载均衡算法
1.介绍
负载均衡算法:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标 ,每次服务重启动后rest接口计数从1开始。
List instances = discoveryClient.getInstances(“CLOUD-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 对应下标位置为0 ,则获得服务地址为127.0.0.1:8002
当总请求数位3时: 3 % 2 =1 对应下标位置为1 ,则获得服务地址为127.0.0.1:8001
当总请求数位4时: 4 % 2 =0 对应下标位置为0 ,则获得服务地址为127.0.0.1:8002
如此类推…
在这里插入代码片
2.手动模仿负载均衡
1)创建接口和类
LoadBanlancer接口:
public interface LoadBalancer {
ServiceInstance instances(List<ServiceInstance> serviceInstances);
}
实现类 MyLB,这里使用了自旋锁 CAS实现原子性操作;compareAndSet方法会判断cuurent和this.atomicInteger.get()是否相同,相同则将this.atomicInteger.get()更新为next,并且退出循环:
具体自旋锁可以看这篇博客:自旋锁
将返回的next与服务总数取余,余数为当前调用的服务下标,返回该服务信息ServiceInstance
@Component
public class MyLB implements LoadBalancer{
private AtomicInteger atomicInteger = new AtomicInteger(0);
public final int getAndIncrement(){
int current;
int next;
do{
current = this.atomicInteger.get();
System.out.println(".... "+current);
next = current>= Integer.MAX_VALUE? 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);
}
}
80端口Controller添加如下代码
获得到服务信息,并且利用restTemplate调用对应的服务实现负载均衡
@Resource
private LoadBalancer loadBalancer;
@Resource
private 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 serviceInstance = loadBalancer.instances(instances);
URI uri = serviceInstance.getUri();
return restTemplate.getForObject(uri+"/payment/lb",String.class);
}
8001,8002端口Controller下添加如下代码
@GetMapping(value = "/payment/lb")
public String getPaymentLB()
{
return serverPort;
}