手写Ribbon负载均衡轮询算法

负载均衡算法:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标  ,每次服务重启动后rest接口计数从1开始。
 
List<ServiceInstance> 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
如此类推......

我这里是用作为Eureka的集群注册中心,

eureka

在你的提供服务的集群模块的Controller中加入:

 @GetMapping(value = "/payment/lb")
    public String getPaymentLB()
    {
        return serverPort;
    }
 

在消费者微服务中也就是端口为80的模块做四件事:

1.ApplicationContextBean中去掉注解@LoadBalanced

@Configuration
public class ApplicationContextConfig
{
    @Bean
//    @LoadBalanced//用于寻找多个服务器,负载均衡
    public RestTemplate getRestTemplate()
    {
        return new RestTemplate();
    }
}

2.LoadBalancer接口

public interface LoadBalancer {
        //创建接口方法
    ServiceInstance instances(List<ServiceInstance> serviceInstances);
}

3.MyLB实现类

@Component
public class MyLB implements LoadBalancer{
        //根据源码来写,此处得到AtomicInteger对象并赋初始值为0
    private AtomicInteger atomicInteger=new AtomicInteger(0);
    public final int getAndIncrement(){
        int current;//目标值
        int next;//跟新值
        do {
            current=this.atomicInteger.get();//获取值
            next=current>=2147483647?0:current+1;//如果该值大于整型数最大值则赋0,防止溢出,否则next=current+1

        }while (!this.atomicInteger.compareAndSet(current,next));//用的CAS的比较,目标值与原值不一致,则更新值,退出while循环
        System.out.println("*****next"+next);
        return next;
    }
    @Override
    public ServiceInstance instances(List<ServiceInstance> serviceInstances) {

        int index=getAndIncrement()%serviceInstances.size();//轮询算法,rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标

        return serviceInstances.get(index);//取得下标为index的服务返回
    }
}

4.OrderController类

@RestController
@Slf4j
public class OrderController
{


    @Resource
    private RestTemplate restTemplate;//注入RestTemplate对象

    @Resource
    private DiscoveryClient discoveryClient;//注入DiscoveryClient对象

    @Resource
    private LoadBalancer loadBalancer;//注入LoadBalancer对象


    @GetMapping("/consumer/payment/lb")
    public String getPaymentLB(){
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");//获取Eureka注册服务中心的服务名称为CLOUD-PAYMENT-SERVICE的服务集合
            if(instances==null||instances.size()<=0){//如果没有就返回null
                return null;
            }
        ServiceInstance serviceInstance = loadBalancer.instances(instances);//调用我们自己写的轮询算法,得到调用的服务
        URI uri = serviceInstance.getUri();//获取该服务的URL
        return restTemplate.getForObject(uri+"/payment/lb",String.class);//转发访问
    }

扫描二维码关注公众号,回复: 15503428 查看本文章

猜你喜欢

转载自blog.csdn.net/JSUITDLWXL/article/details/124821558