category
学习思考
date
Jul 23, 2022
icon
Origin
password
slug
LoadBalanceAlgorithm
status
Published
summary
对于负载均衡算法的一些理解
tags
Tags
type
Post

原理:

负载均衡算法:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器为止下标 , 每次服务重启动后rest接口计数从 1 开始。
 
List<ServiceInstance> instances = discoveryClient.gentInstances(”CLOUD-PAYMENT-SERVICE”);
 
如:
List[0] instances = 127.0.0.1:8001
List[1] instances = 127.0.0.1:8002
8001 和 8002 组合成为集群,他们共计2台服务器,集群总数为2,按照轮训算法原理:
 
当总请求数为 1 时:1 % 2 = 1 对应下标位置为 1 ,则获得服务地址为 127.0.0.1:8001
当总请求数为 2 时:1 % 2 = 0 对应下标位置为 0,则获得服务地址为 127.0.0.1:8002
当总请求数为 3 时:1 % 2 = 1 对应下标位置为 0 ,则获得服务地址为 127.0.0.1:8001
当总请求数为 4 时:1 % 2 = 0 对应下标位置为 1 ,则获得服务地址为 127.0.0.1:8002
以此类推……

源码:

notion image
IRule接口时com.netflix.loadbalancer包下的一个接口,mac操作系统下,idea软件按住control + h 可以看到他的实现类,如下图所示:
notion image
我们选择RoundRobinRule实现类,发现它继承了AbstractLoadBalancerRule接口
notion image
通过源码我们可以看出:
他的构造方法加了一个原子整型类 AtomicInteger , 默认值为 0
choose方法中先判断 lb 的值,如果为 null,则返回 null,并输出“no load balancer” ,没有负载均衡
若有值,创建 server 和 count ,创建一个可达的 reachableServers的list和 所有server的allServers,他们的大小分别是upCountserverCount,如果这两个count同时不为0,计算出nextServerIndex的角标 ,这里incrementAndGetModulo 方法用到了CAS的算法,判断取余数后的数是否有人动过,若没有动过就返回余数,这个余数就是nextServerIndex。这是一种自旋锁的思想。然后去allServers 里面取下标为nextServerIndex的服务,然后把服务返回。

手写:

如何自己实现一个负载均衡? 下面是我的尝试。
新建LoadBalancer接口 接口中有一个方法,获取服务实例
LoadBalancer.Interface
public interface LoadBalacner { ServiceInstance instances(List<ServiceInstance> serviceInstances); }
MyLB实现这个接口: MyLB.java
@Component public class MyLB implements LoadBalacner{ 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; }while (!this.atomicInteger.compareAndSet(current,next)); System.out.println("********第几次访问,次数next:" + next); return next; } @Override public ServiceInstance instances(List<ServiceInstance> serviceInstances) { int index = getAndIncrement() % serviceInstances.size(); return serviceInstances.get(index); } }
服务调用
@GetMapping(value = "/consumer/payment/lb") public String getPaymentLB(){ List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE"); if(instances == null || instances.size() <= 0){ return null; } ServiceInstance serviceInstance = loadBalacner.instances(instances); URI uri = serviceInstance.getUri(); return restTemplate.getForObject(uri+"/payment/lb",String.class); }
服务端方法:
@GetMapping(value = "/payment/lb") public String getPaymentLB(){ return serverPort; }
结果:
notion image
Hystrix服务降级框架记录一次奇怪的问题排查

  • Twikoo
  • Giscus