List 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,则获得服务地址为127.0.0.1:8002
当总请求数位3时:3%2=1对应下标位置为1,则获得服务地址为127.0.0.1:8001
当总请求数位4时:4%2=О对应下标位置为0,则获得服务地址为127.0.0.1:8002
如此类推…
RoundRobinRule 源码分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
public interface IRule{ /* * choose one alive server from lb.allServers or * lb.upServers according to key * * @return choosen Server object. NULL is returned if none * server is available */ //重点关注这方法 public Server choose(Object key); public void setLoadBalancer(ILoadBalancer lb); public ILoadBalancer getLoadBalancer(); }
package com.netflix.loadbalancer; import com.netflix.client.config.IClientConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** * The most well known and basic load balancing strategy, i.e. Round Robin Rule. * * @author stonse * @author Nikos Michalakis <nikos@netflix.com> * */ public class RoundRobinRule extends AbstractLoadBalancerRule { private AtomicInteger nextServerCyclicCounter; private static final boolean AVAILABLE_ONLY_SERVERS = true; private static final boolean ALL_SERVERS = false; private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class); public RoundRobinRule() { nextServerCyclicCounter = new AtomicInteger(0); } public RoundRobinRule(ILoadBalancer lb) { this(); setLoadBalancer(lb); } //重点关注这方法。 public Server choose(ILoadBalancer lb, Object key) { if (lb == null) { log.warn("no load balancer"); return null; } Server server = null; int count = 0; while (server == null && count++ < 10) { List<Server> reachableServers = lb.getReachableServers(); List<Server> allServers = lb.getAllServers(); int upCount = reachableServers.size(); int serverCount = allServers.size(); if ((upCount == 0) || (serverCount == 0)) { log.warn("No up servers available from load balancer: " + lb); return null; } int nextServerIndex = incrementAndGetModulo(serverCount); server = allServers.get(nextServerIndex); if (server == null) { /* Transient. */ Thread.yield(); continue; } if (server.isAlive() && (server.isReadyToServe())) { return (server); } // Next. server = null; } if (count >= 10) { log.warn("No available alive servers after 10 tries from load balancer: " + lb); } return server; } /** * Inspired by the implementation of {@link AtomicInteger#incrementAndGet()}. * * @param modulo The modulo to bound the value of the counter. * @return The next value. */ private int incrementAndGetModulo(int modulo) { for (;;) { int current = nextServerCyclicCounter.get(); int next = (current + 1) % modulo;//求余法 if (nextServerCyclicCounter.compareAndSet(current, next)) return next; } } @Override public Server choose(Object key) { return choose(getLoadBalancer(), key); } @Override public void initWithNiwsConfig(IClientConfig clientConfig) { } }
Ribbon 之手写轮询算法
自己试着写一个类似 RoundRobinRule 的本地负载均衡器。
7001/7002 集群启动
1. 8001/8002 微服务改造 - controller
1 2 3 4 5 6 7 8 9 10
@RestController @Slf4j public class PaymentController{ ... @GetMapping(value = "/payment/lb") public String getPaymentLB() { return serverPort;//返回服务接口 } ... }
package com.sevattal.springcloud.lb; import org.springframework.cloud.client.ServiceInstance; import org.springframework.stereotype.Component; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** */ @Component//需要跟主启动类同包,或者在其子孙包下。 public class MyLB implements LoadBalancer { 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; } //负载均衡算法:rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标 ,每次服务重启动后rest接口计数从1开始。 @Override public ServiceInstance instances(List<ServiceInstance> serviceInstances) { int index = getAndIncrement() % serviceInstances.size(); return serviceInstances.get(index); } }