负载测试结果如下:
可以看到第二个机器会有50%的请求,最后一台机器只有17%的请求,负载的情况并不是很均匀,我认为通过IP负载并不是一个好的方案。
还记得我们之前讲过Ribbon默认的轮询算法RoundRobinRule,【一起学源码-微服务】Ribbon 源码四:进一步探究Ribbon的IRule和IPing 。
这种算法就是一个很好的散列算法,可以保证每次请求都很均匀,原理如下图:
还是先上结论,如下图:
我们的serverList按照client端的ip进行重排序后,每次都会请求第一个元素作为和Server端交互的host,如果请求失败,会尝试请求serverList列表中的第二个元素继续请求,这次请求成功后,会将此次请求的host放到全局的一个变量中保存起来,下次client端再次请求 就会直接使用这个host。
这里最多会重试请求两次。
代码实现直接看底层交互的代码,位置在
com.netflix.discovery.shared.transport.decorator.RetryableEurekaHttpClient.execute() 中:
我们来分析下这个代码:
第101行,获取client上次成功server端的host,如果有值则直接使用这个host
第105行,getHostCandidates()是获取client端配置的serverList数据,且通过ip进行重排序的列表
第114行,candidateHosts.get(endpointIdx++),初始endpointIdx=0,获取列表中第1个元素作为host请求
第120行,获取返回的response结果,如果返回的状态码是200,则将此次请求的host设置到全局的delegate变量中
第133行,执行到这里说明第120行执行的response返回的状态码不是200,也就是执行失败,将全局变量delegate中的数据清空
再次循环第一步,此时endpointIdx=1,获取列表中的第二个元素作为host请求
依次执行,第100行的循环条件numberOfRetries=3,最多重试2次就会跳出循环
我们还可以第123和129行,这也正是我们业务抛出来的日志信息,所有的一切都对应上了。
总结感谢你看到这里,相信你已经清楚了开头提问的问题。
上面已经分析完了Eureka集群下Client端请求时负载均衡的选择以及集群故障时自动重试请求的实现原理。
如果还有不懂的问题,可以添加我的微信或者给我公众号留言,我会单独和你讨论交流。
本文首发自:一枝花算不算浪漫 公众号,如若转载请在文章开头标明出处,如需开白可直接公众号回复即可。