前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Ribbon之手写轮询算法

Ribbon之手写轮询算法

作者头像
Li_XiaoJin
发布2022-06-10 21:12:54
2960
发布2022-06-10 21:12:54
举报
文章被收录于专栏:Lixj's BlogLixj's Blog

最近在学习Spring Cloud的相关内容,记录一下。

先说一下 Ribbon 轮询算法的逻辑:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标,每次服务重启动后rest接口计数从1开始。

源代码如下: 采用的是自旋锁。

接下来我们也手写一下这个逻辑。

  1. 代码中的 @LoadBalanced 要注释掉,不然我们自己写的轮询代码就不生效了。

  1. 新建一个 LoadBalance 的接口类
代码语言:javascript
复制
public interface LoadBalance {

    ServiceInstance instance(List<ServiceInstance> serviceInstanceList);

}
  1. 再写实现类
代码语言:javascript
复制
// 记得加上这个注解
@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操作时,就会继续进行比较并替换的操作直到成功为止,自旋锁不是重量级锁,他可以提高多线程情况下效率

  1. 调用轮询负载算法进行测试
代码语言:javascript
复制
@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 该微服务名称的微服务 List2.调用上面自定义的负载均衡轮询类中的 instances 方法,获取出调用的微服务实例3.获取该实例中的 URI 地址,使用 restTemplate 进行服务调用

访问 http://localhost/test/lb 可以看到日志中次数在不断增加

如果把后面调用的服务输出到页面上,也可以看到在几个服务中轮询调用~

关于自旋锁,我还要再学习一番,改天针对自旋锁单独写一篇。-_-

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可 Links: https://lixj.fun/archives/ribbon之手写轮询算法

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-03-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
负载均衡
负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档