欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SpringCloud篇之手写轮询算法(Ribbon轮询算法)

程序员文章站 2023-01-13 19:48:45
本片主要介绍SpringCloud中基于netflix 的Ribbon负载均衡中的轮询机制。Ribbon不同于Nginx,Ribbon是本地负载均衡,而Nginx是客户端负载均衡,作用点不同。Ribbon主要是对服务接口调用的一种负载机制。在Ribbon中,以IRule作为负载策略。其中默认的是轮询机制,本篇即模仿Ribbon手写一个轮询算法。先来看看IRule的继承关系其中的RoundRobinRule就是轮询策略下面我们开始手写一个轮询策略首先事先做好我们的基本环境,这......

本片主要介绍SpringCloud中基于netflix 的Ribbon负载均衡中的轮询机制。

Ribbon不同于Nginx,Ribbon是本地负载均衡,而Nginx是客户端负载均衡,作用点不同。Ribbon主要是对服务接口调用的一种负载机制。在Ribbon中,以IRule作为负载策略。其中默认的是轮询机制,本篇即模仿Ribbon手写一个轮询算法。

先来看看IRule的继承关系

SpringCloud篇之手写轮询算法(Ribbon轮询算法)

其中的RoundRobinRule就是轮询策略

下面我们开始手写一个轮询策略

首先事先做好我们的基本环境,这里使用的是Eureka作为服务与发现注册中心

服务注册中心

SpringCloud篇之手写轮询算法(Ribbon轮询算法)

服务提供者

为了达到负载测试的效果,这里需要提供两个服务提供者

SpringCloud篇之手写轮询算法(Ribbon轮询算法)

服务消费者

SpringCloud篇之手写轮询算法(Ribbon轮询算法)

搭建好基本的机构之后我们开始编写我们的轮询算法

1、创建核心接口--用于调用目标服务

/**
 * 轮询接口
 */
public interface LoadBalance {

    ServiceInstance getInstance(List<ServiceInstance> serviceInstances);
}

2、创建接口实现类--编写核心算法

@Component
public class MyLoadBalancer implements LoadBalance {


    //原子封装类
    private AtomicInteger atomicInteger = new AtomicInteger(0);

    /**
     * 计算得到当前调用次数
     * @return
     */
    public final int getAndIncrement(){
        int current;
        int next;

        do {
            current = atomicInteger.get();
            next = current >= Integer.MAX_VALUE ? 0 : current+1;
        }while (!atomicInteger.compareAndSet(current,next));   //利用CAS保证原子操作

        return next;
    }


    /**
     * 轮询算法
     * 当前调用数 % 服务实例数量
     * @param serviceInstances
     * @return
     */
    @Override
    public ServiceInstance getInstance(List<ServiceInstance> serviceInstances) {
        int index = this.getAndIncrement() % serviceInstances.size();
        //根据下标返回对应的服务实例
        return serviceInstances.get(index);
    }
}

3、策略调用

@RestController
@Slf4j
public class OrderController {

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private MyLoadBalancer myLoadBalancer;

    @Resource
    private DiscoveryClient discoveryClient;



    @GetMapping(value = "/consumer/payment/getInstance/{id}")
    public GeneralResult<Integer> getPaymentByInstance(@PathVariable("id")Long id){
        //获取所有服务实例
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        if(instances == null || instances.size() <= 0){
            return null;
        }
        //根据我们的轮询算法得到对应的服务实例
        ServiceInstance instance = myLoadBalancer.getInstance(instances);
        //根据服务实例获得服务器的uri
        URI uri = instance.getUri();
        return restTemplate.getForObject(uri+"cloud/payment/get/"+id,GeneralResult.class);
    }
}

至此我们的服务轮询机制已经完成

最后我们可以看到每一次请求都循环更换端口

SpringCloud篇之手写轮询算法(Ribbon轮询算法)

SpringCloud篇之手写轮询算法(Ribbon轮询算法)

本文地址:https://blog.csdn.net/weixin_44245778/article/details/107391072