IRule是一个接口,其源码如下:
package com.netflix.loadbalancer; /** * Interface that defines a "Rule" for a LoadBalancer. A Rule can be thought of * as a Strategy for loadbalacing. Well known loadbalancing strategies include * Round Robin, Response Time based etc. * * @author stonse * */ 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(); }以下是IRule接口的部分实现,这些实现分别对应了若干负载均衡算法
以下简要说明7种主要的负载均衡算法,这些负载均衡算法均是抽象类com.netflix.loadbalancer.AbstractLoadBalancerRule 的实现,而给抽象类实现了IRule接口:
com.netflix.loadbalancer.RoundRobinRule:轮询,为默认的负载均衡算法
com.netflix.loadbalancer.RandomRule:随机
com.netflix.loadbalancer.RetryRule:先按照RoundRobinRule(轮询)的策略获取服务,如果获取服务失败则在指定时间内进行重试,获取可用的服务
com.netflix.loadbalancer.WeightedResponseTimeRule:对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择。
com.netflix.loadbalancer.BestAvailableRule:先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
com.netflix.loadbalancer.AvailabilityFilteringRule:先过滤掉故障实例,再选择并发较小的实例
com.netflix.loadbalancer.ZoneAvoidanceRule:复合判断Server所在区域的性能和Server的可用性选择服务器
3.2 如何替换负载均衡算法服务消费者80添加轮询算法配置类
首先我们应该明确是服务消费方采用轮询算法来访问同一服务提供方的不同微服务实例,所以我们应该在服务消费方80方的微服务中添加轮询算法配置类。
在添加配置类时,有必须要注意的点,就是官方文档明确给出了警告:这个自定义的轮询算法配置类不能放在@ComponentScan注解所扫描的当前包下以及子包下,否则自定义的这个配置类就会被所有Ribbon客户端所共享,就达不到特殊化定制的目的了。换句话说,如果这个配置类我们能够被@ComponentScan注解扫描到,那么访问所有的微服务提供方的具体实例时,我们都会采取配置类中的算法,如果要特殊化定制 - 即指定访问某些微服务提供方时采用配置的轮询算法,那么我们就应该使这个配置类让@ComponentScan注解扫描不到,我们知道在主启动类的@SpringBootApplication注解中,其实这个注解包含了@SpringBootConfiguration 、@EnableAutoConfiguration、@ComponentScan这三个注解,所以我们写的轮询算法配置类不能和主启动类在同一个包下,所以我们需要建新的包,实现定制轮询算法的配置类:
package com.polaris.myrule; /** * @author polaris */ @Configuration public class MySelfRule { @Bean public IRule myRule() { return new RandomRule(); //定义随机负载均衡算法 } }包结构的内容如下,我们可以看到,轮询算法配置类在主启动类的@ComponentScan扫描不到的包下:
服务消费者80主启动类中添加@RibbonClient注解
@SpringBootApplication @EnableEurekaClient //访问的微服务为CLOUD-PAYMENT-SERVICE,采用配置文件中的轮询算法 @RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class) public class OrderMain { public static void main(String[] args) { SpringApplication.run(OrderMain80.class); } }测试
测试发现我们用服务消费方访问服务提供方的微服务时,8001和8002不再交替轮询访问,而是随机访问。
4. Ribbon负载均衡算法 4.1 默认负载均衡算法(轮询)原理轮询负载均衡算法原理:Rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标, 每次服务重启后Rest接口计数从1开始。
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE")根据服务方的服务名,获取其所有实例,如有以下实例:
List[0] List[1]服务名 payment8001 payment8002
服务地址 127.0.0.1:8001 127.0.0.1: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.2 轮询源码分析