点击上方"蓝字", 右上角选择“设为星标”
周一至五早8点半!精品技术文章准时送上!

上篇文章我们介绍了SpringCloud的负载均衡组件Ribbon的基础理论以及完成服务消费方是如何通过Ribbon实现负载均衡的具体操作配置。具体详情参见《【SpringCloud】SpringCloud Ribbon负载均衡》。
本篇内容我们还是讲一讲Ribbon的一个核心的组件IRule。
前面我们说到Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接服务提供方得到机器,而IRule就是制定Ribbon要用什么样的规则来实现负载均衡的。
简单的说:IRule就是根据特定算法中从服务列表中选取一个要访问的服务。而默认采用轮询算法。

IRule主要有七中已经制定好的算法:
RoundRobinRule 轮询
RandomRule 随机
RetryRule
先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务
AvailabilityFilteringRule
会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问
WeightedResponseTimeRule
根据平均响应时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越高。刚启动时如果统计信息不足,则使用RoundRobinRule策略,等统计信息足够,会切换到WeightedResponseTimeRule
BestAvailableRule
会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
ZoneAvoidanceRule
默认规则,复合判断server所在区域的性能和server的可用性选择服务器
上面说过IRule的默认算法是轮询规则,那么问题来了我怎么样才能用其他六种规则呢?下面我们就来实现一下如果覆盖默认的算法。这里我们需要对工程cnzx-consumer-8021进行简单的修改。
package com.cnzx.consumer.cfgbeans; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; @Configuration public class ConfigBean { @Bean @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); } @Bean public IRule myRule() { // 覆盖默认的轮询算法为随机算法 return new RandomRule(); } } |
只要加上上面红色字体的内容就可以了。
首先我们先启动Eureka的三个集群工程cnzx-eureka-8031/cnzx-eureka-8032/cnzx-eureka-8033,然后在把服务提供者的工程cnzx-provider-8011启动,最后在启动服务消费方的工程cnzx-consumer-8021。
然后分别访问:http://127.0.0.1:8021/dept/list,不断的刷新可以看出获取的结果已经不是轮询算法了,而是毫无规律的随机算法。
当IRule自带的算法无法满足某个业务需求时,我们需要自己根据需求自定义算法,那么这种情况我们该怎么做呢?我们先来看下官网怎么说的:

看上面红圈的内容:The FooConfiguratuib has to be @Configuration but take care it is not in a @ComponentScan for the main application context.意思就是那个自定义的规则算法必须要有@Configuration注解,但是要注意,它不能在@ComponentScan扫描的包下,也就是不能与启动类同级或者下级,否则所有的服务算法都用你自定义的,达不到特殊化定制的目的了。
下面我们来具体操作下步骤如下:
刚开始介绍算法时有张图,从图上可以看出所有的算法都继承了一个抽象的类AbstractLoadBalancerRule。
所以具体算法例子如下:依旧轮询策略,但是加上新需求,每个服务器要求被调用5次。 也即以前是每台机器一次,现在是每台机器5次
package com.cnzx.myrule; import java.util.List; import org.springframework.context.annotation.Configuration; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.AbstractLoadBalancerRule; import com.netflix.loadbalancer.ILoadBalancer; import com.netflix.loadbalancer.Server; public class MyDefineRule extends AbstractLoadBalancerRule { // 总共被调用的次数,目前要求每台被调用5次 private int total = 0; // 当前提供服务的机器号 private int currentIndex = 0; public Server choose(ILoadBalancer lb, Object key) { if (lb == null) { return null; } Server server = null; while (server == null) { if (Thread.interrupted()) { return null; } List List int serverCount = allList.size(); if (serverCount == 0) { return null; } if (total < 5) { server = upList.get(currentIndex); total++; } else { total = 0; currentIndex++; if (currentIndex >= upList.size()) { currentIndex = 0; } } if (server == null) { Thread.yield(); continue; } if (server.isAlive()) { return (server); } server = null; Thread.yield(); } return server; } @Override public Server choose(Object key) { return this.choose(getLoadBalancer(), key); } @Override public void initWithNiwsConfig(IClientConfig arg0) { } } |
上面说过在这个类必须加上@Configuration注解,说明这个类是配置类。
代码如下:
| package com.cnzx.myrule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.netflix.loadbalancer.IRule; @Configuration public class MyConfigRule { @Bean public IRule myIRule() { return new RoundRobinRuleNew(); } } |
这里直接在启动类上添加@RibbonClient注解,使得自定义得算法规则生效。
package com.cnzx.consumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.ribbon.RibbonClient; import com.cnzx.myrule.RoundRobinRuleNew; @SpringBootApplication @EnableEurekaClient @RibbonClient(name = "CNZX-PROVIDER", configuration = RoundRobinRuleNew.class) public class ConsumerAppStart8021 { public static void main(String[] args) { SpringApplication.run(ConsumerAppStart8021.class, args); } } |
重新启动cnzx-consumer-8021工程,浏览器访问:http://127.0.0.1:8021/dept/list,在不断刷新可以看出Ribbon的负载均衡算法已经变为我们自定义的算法了。
下篇文章我们来说说SpringCloud的另外一个组件SpringCloud Feign《【SpringCloud】SpringCloud Feign负载均衡(客户端)》

更多Java、数据库、微服务、分布式的原创系列文章正在路上,欢迎扫描下方二维码,持续关注:

灵动思维文化传媒(id:itjhzx)
多年技术经验倾囊相授





