一、Ribbon的核心组件IRule
● IRule:根据特定算法从服务列表中选取一个要访问的服务,默认是轮询算法
● github上的源码地址:https://github.com/Netflix/ribbon/tree/master/ribbon-loadbalancer
● 以下列举一些算法:
(1)、RoundRobinRule(轮询)
(2)、RandomRule(随机)
(3)、AvailabilityFilteringRule:此算法会先过滤由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接
数量超过阈值的服务,然后对剩余的服务列表按照轮询策略进行访问
(4)、WeightedResponseTimeRule:根据平均响应时间计算所有服务的权重,响应时间越快服务权重越大,被选中的概率
越高,刚启动时如果统计信息不足,则使用RoundRobinRule策略,等统计信息足够,会切换到WeightedResponseTimeRule
(5)、RetryRule:先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的
服务
(6)、BestAvailableRule:会先过滤由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
(7)、ZoneAvoidanceRule:默认规则,复合判断server所在区域的性能和server的可用性选择服务器
二、Ribbon根据需要指定算法
只需要在配置类(使用@Configuration修饰的类)中注入相应算法的Bean即可,例如:
@Configuration
public class ConfigBean {
@LoadBalanced //开启负载均衡
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
/**
* 默认是轮询算法,修改为随机算法
* @return
*/
@Bean
public IRule getIRule() {
return new RandomRule();
}
}
Ribbon 的 负载均衡策略源码 Github地址:
https://github.com/Netflix/ribbon/blob/master/ribbon-loadbalancer/src/main/java/com/netflix/loadbalancer/RandomRule.java
三、自定义Ribbon的负载均衡策略
(1)、在主配置类上添加如下注解,作用是:在启动该微服务的时候就能去加载我们自定义的Ribbon配置类,从而使配置生效
@RibbonClient(value="微服务名称", configuration=自定义配置类.class)
例如:@RibbonClient(value = "MICROSERVICECLOUD-DEPT", configuration = {MySelfRule.class})
(2)、修改 / 自定义 负载均衡策略的写法:
@Configuration
public class MySelfRule {
@Bean
public IRule getIRule() {
/**
* 修改Ribbon 负载均衡策略
*/
//return new RandomRule(); //默认轮询,自定义为随机
/**
* 自定义 Ribbon 负载均衡策略
*/
return new MyRandomRule();
}
}
(3)、自定义负载均衡策略的写法:(根据github上的Ribbon 负载均衡源码,读源码,根据源码进行修改)
/**
* @Description: 自定义Ribbon的负载均衡策略: 依旧是轮询策略,但是加上新需求,每个服务器要求被调用5次,
* 也即以前是每台机器一次,现在是每台机器5次
* @Author: zlj
* @CreateDate: 2018/6/22 10:46
* @Version: 1.0.0
*/
public class MyRandomRule extends AbstractLoadBalancerRule {
//总调用次数,目前要求每台被调用5次,当 total == 5时,currentIndex++,然后total需要重新置0
private Integer total = 0;
private Integer currentIndex = 0; //当前对外提供的微服务的索引(下标)
/**
* Randomly choose from all living servers
*/
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
Server server = null;
while (server == null) {
if (Thread.interrupted()) {
return null;
}
List<Server> upList = lb.getReachableServers();
List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0) {
/*
* No servers. End regardless of pass, because subsequent passes
* only get more restrictive.
*/
return null;
}
//====================start===============================
//修改源码内容,添加自定义逻辑
if (total < 5) {
server = upList.get(currentIndex);
total++;
} else {
total = 0;
currentIndex++;
if (currentIndex >= upList.size()) {
currentIndex = 0;
}
}
//====================end===============================
if (server == null) {
/*
* The only time this should happen is if the server list were
* somehow trimmed. This is a transient condition. Retry after
* yielding.
*/
Thread.yield();
continue;
}
if (server.isAlive()) {
return (server);
}
// Shouldn't actually happen.. but must be transient or a bug.
server = null;
Thread.yield();
}
return server;
}
@Override
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
// TODO Auto-generated method stub
}
}
(4)、注意配置细节:
官方文档上说:这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下,否则我们自定义的这个配置
类就会被所有的Ribbon客户端共享,这样就达不到特殊化定制(即为指定的微服务配置指定的负载均衡策略)的目的。
网友评论