>最近在学习Spring Cloud的相关内容,记录一下。
先说一下 Ribbon 轮询算法的逻辑:**rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标,每次服务重启动后rest接口计数从1开始。**
源代码如下:
采用的是自旋锁。

接下来我们也手写一下这个逻辑。
1. 代码中的 @LoadBalanced 要注释掉,不然我们自己写的轮询代码就不生效了。

2. 新建一个 LoadBalance 的接口类
```
public interface LoadBalance {
ServiceInstance instance(List<ServiceInstance> serviceInstanceList);
}
```
3. 再写实现类
```
// 记得加上这个注解
@Component
public class MyLB implements LoadBalance {
// 设置原子类Integer,初始化为 0
private AtomicInteger atomicInteger = new AtomicInteger(0);
/**
* 通过CAS +自旋锁的方式 返回一个调用该微服务的次数
*/
public final int getAndIncreament() {
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 instance(List<ServiceInstance> serviceInstanceList) {
// 获取当前访问的次数后,与当前服务的数量取余,算出服务的下标
int index = getAndIncreament() % serviceInstanceList.size();
// 返回对应下标的服务
return serviceInstanceList.get(index);
}
}
```
>采用CAS+自旋锁的原因:由于负载均衡使用的场景是高并发,而轮询算法的核心是得到一个整数型的下标,在高并发的场景下,需要保证该下标的数据一致性,CAS可以保证该下标的数据一致性,自旋锁可以使该次请求不断的访问重试直到成功为止,CAS+自旋锁的原因是可以在高效率和安全性的情况下保证微服务的高可用。
>comapreAndSet底层采用了comapreAndSwap,比较并替换是一个在硬件方面上实现的原子性操作把,比较并替换变成了一步操作(可以理解成相当于加了一个锁),这样就可以保证在多线程的情况下,该下标只能被一个线程比较并替换,这样就保证了共享变量的安全性
>自旋锁的实现方式有很多种,这里采用了do....while循环,这里自旋锁的作用是,当某一个线程不满足CAS操作时,就会继续进行比较并替换的操作直到成功为止,自旋锁不是重量级锁,他可以提高多线程情况下效率
4. 调用轮询负载算法进行测试
```
@RestController
public class LBController {
@Resource
private RestTemplate restTemplate;
@Resource
private LoadBalance loadBalance;
@Resource
private DiscoveryClient discoveryClient;
@GetMapping(value = "test/lb")
public String getLBService() {
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PROVIDER-SERVICE");
if (instances == null || instances.size() <= 0) {
return null;
}
ServiceInstance serviceInstance = loadBalance.instance(instances);
URI uri = serviceInstance.getUri();
return restTemplate.getForObject(uri + "/test/lb" ,String.class);
}
}
```
>1.获取 CLOUD-PROVIDER-SERVICE 该微服务名称的微服务 List
2.调用上面自定义的负载均衡轮询类中的 instances 方法,获取出调用的微服务实例
3.获取该实例中的 URI 地址,使用 restTemplate 进行服务调用
访问 http://localhost/test/lb
可以看到日志中次数在不断增加

如果把后面调用的服务输出到页面上,也可以看到在几个服务中轮询调用~
>关于自旋锁,我还要再学习一番,改天针对自旋锁单独写一篇。-_-


Ribbon之手写轮询算法