一个线上问题的思考:Eureka注册中心集群如何实现客户端请求负载及故障转移? (2)

负载原理.png

这里会以EurekaClient端的IP作为随机的种子,然后随机打乱serverList,例如我们在商品服务(192.168.10.56)中配置的注册中心集群地址为:peer1,peer2,peer3,打乱后的地址可能变成peer3,peer2,peer1。

用户服务(192.168.22.31)中配置的注册中心集群地址为:peer1,peer2,peer3,打乱后的地址可能变成peer2,peer1,peer3。

EurekaClient每次请求serverList中的第一个服务,从而达到负载的目的。

代码实现

我们直接看最底层负载代码的实现,具体代码在
com.netflix.discovery.shared.resolver.ResolverUtils.randomize() 中:

代码实现.png

这里面random 是通过我们EurekaClient端的ipv4做为随机的种子,生成一个重新排序的serverList,也就是对应代码中的randomList,所以每个EurekaClient获取到的serverList顺序可能不同,在使用过程中,取列表的第一个元素作为server端host,从而达到负载的目的。

负载均衡代码实现.png

思考

原来代码是通过EurekaClient的IP进行负载的,所以刚才通过DEMO程序结果就能解释的通了,因为我们做实验都是用的同一个IP,所以每次都是会访问同一个Server节点。

既然说到了负载,这里肯定会有另一个疑问:

通过IP进行的负载均衡,每次请求都会均匀分散到每一个Server节点吗?

比如第一次访问Peer1,第二次访问Peer2,第三次访问Peer3,第四次继续访问Peer1等,循环往复......

我们可以继续做个试验,假如我们有10000个EurekaClient节点,3个EurekaServer节点。

Client节点的IP区间为:192.168.0.0 ~ 192.168.255.255,这里面共覆盖6w多个ip段,测试代码如下:

/** * 模拟注册中心集群负载,验证负载散列算法 * * @author 一枝花算不算浪漫 * @date 2020/6/21 23:36 */ public class EurekaClusterLoadBalanceTest { public static void main(String[] args) { testEurekaClusterBalance(); } /** * 模拟ip段测试注册中心负载集群 */ private static void testEurekaClusterBalance() { int ipLoopSize = 65000; String ipFormat = "192.168.%s.%s"; TreeMap<String, Integer> ipMap = Maps.newTreeMap(); int netIndex = 0; int lastIndex = 0; for (int i = 0; i < ipLoopSize; i++) { if (lastIndex == 256) { netIndex += 1; lastIndex = 0; } String ip = String.format(ipFormat, netIndex, lastIndex); randomize(ip, ipMap); System.out.println("IP: " + ip); lastIndex += 1; } printIpResult(ipMap, ipLoopSize); } /** * 模拟指定ip地址获取对应注册中心负载 */ private static void randomize(String eurekaClientIp, TreeMap<String, Integer> ipMap) { List<String> eurekaServerUrlList = Lists.newArrayList(); eurekaServerUrlList.add("http://peer1:8080/eureka/"); eurekaServerUrlList.add("http://peer2:8080/eureka/"); eurekaServerUrlList.add("http://peer3:8080/eureka/"); List<String> randomList = new ArrayList<>(eurekaServerUrlList); Random random = new Random(eurekaClientIp.hashCode()); int last = randomList.size() - 1; for (int i = 0; i < last; i++) { int pos = random.nextInt(randomList.size() - i); if (pos != i) { Collections.swap(randomList, i, pos); } } for (String eurekaHost : randomList) { int ipCount = ipMap.get(eurekaHost) == null ? 0 : ipMap.get(eurekaHost); ipMap.put(eurekaHost, ipCount + 1); break; } } private static void printIpResult(TreeMap<String, Integer> ipMap, int totalCount) { for (Map.Entry<String, Integer> entry : ipMap.entrySet()) { Integer count = entry.getValue(); BigDecimal rate = new BigDecimal(count).divide(new BigDecimal(totalCount), 2, BigDecimal.ROUND_HALF_UP); System.out.println(entry.getKey() + ":" + count + ":" + rate.multiply(new BigDecimal(100)).setScale(0, BigDecimal.ROUND_HALF_UP) + "%"); } } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwwwjz.html