在Ribbon负载均衡中 他默认的负载均衡为轮询 下面就来手撕一个轮询算法 第一步 先定义好接口
public interface LoadBalancer {
/**
* 负载均衡算法规则公式: rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标
* 每次服务重启后rest接口计数从1开始
*/
public ServiceInstance instaces(List<ServiceInstance> serviceInstances);
}
第二步:写实现类
@Component
public class MyLB implements LoadBalancer{
//原子类 因为底层的轮询算法初始化这个值为0 所以这里我们也将其配置为0
private AtomicInteger atomicInteger = new AtomicInteger(0);
//获取请求数
public final int getAndIncrement(){
int current; //期望值
int next; //请求次数
do {
current = this.atomicInteger.get(); //获取当前的值
/**
* 2147483647为Integer最大值
*/
next = current >= 2147483647 ? 0 : current + 1;
}while (!this.atomicInteger.compareAndSet(current,next));
System.out.println("next:" + next);//打印请求数并返回
return next;
}
@Override //重写接口中的方法获取服务实例下标来判断端口
public ServiceInstance instaces(List<ServiceInstance> serviceInstances) {
/**
* index:实际调用服务器位置下标
* getAndIncrement:rest接口第几次请求数
* serviceInstances.size(); 服务器集群总数量
*/
int index = getAndIncrement() % serviceInstances.size();
return serviceInstances.get(index);
}
}
第三步 将这个LoadBalancer 注入到Controller 此时我们可以看到 注入的这个LoadBalancer 是我们自定义写好的
第四步 在controller中 继续写入 具体实现
@GetMapping("/consumer/payment/lb") //轮询访问路径
public String getPaymentLB(){
//定义Eureka注册中心的服务名
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
if(instances == null || instances.size() <= 0){
//如果instances等于空或者小于0的话 直接返回一个空值
return null;
}
//通过注入的loadBalancer可以用到我们写好的instaces()方法 再把我们定义的instances放到这里就可以了
ServiceInstance serviceInstance = loadBalancer.instaces(instances);
//通过获取的服务实例 就可以获取到 uri
URI uri = serviceInstance.getUri();
//返回到页面的就是我们的端口号 由此来实验 是否为轮询
return restTemplate.getForObject(uri+"/payment/lb",String.class);
}