Ribbon中的内置的负载均衡算法,都实现了IRule接口。因此如果我们要自定时负载均衡算法也要实现IRule接口。
IRule接口:
public interface IRule {
Server choose(Object var1); //选择哪个服务处理请求
void setLoadBalancer(ILoadBalancer var1); //设置ILoadBalancer 类型的变量信息
ILoadBalancer getLoadBalancer(); //获取ILoadBalancer 类型的变量信息
}
Ribbon中已经实现了IRule接口的类:这些类都是Ribbon中的负载均衡算法,抽象类除外。
IRule接口中有两个类型值得注意:Server和ILoadBalancer。Server封装了是注册进Eureka的微服务信息,也就代表注册进Eureka的微服务。而ILoadBalancer是一个接口,用来获取注册进Eureka的全部或部分或某个微服务信息,如下:
public interface ILoadBalancer {
void addServers(List<Server> var1);
Server chooseServer(Object var1);
void markServerDown(Server var1);
/** @deprecated */
@Deprecated
List<Server> getServerList(boolean var1);
List<Server> getReachableServers();
List<Server> getAllServers();
}
到这里可以看出,IRule接口是通过ILoadBalancer来获取Server,进而实现负载均衡。下面我们以RandomRule为例分析IRule如何实现负载均衡,以及我们如何自定义实现负载均衡.
RandomRule:负载均衡随机算法
public class RandomRule extends AbstractLoadBalancerRule {
Random rand = new Random();
public RandomRule() {
}
//负载均衡算法的主要实现逻辑
@SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
} else {
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)
return null;
int index = this.rand.nextInt(serverCount);
server = (Server)upList.get(index);
if (server == null) {
Thread.yield(); //让出CPU,让当前线程和其他线程可执行。相当于重新争夺资源
} else {
if (server.isAlive()) {
return server;
}
server = null;
Thread.yield();
}
}
return server; //返回随机获取的可用的微服务
}
}
//直接调用 choose(ILoadBalancer lb, Object key)方法
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
//空方法
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
RandomRule继承了AbstractLoadBalancerRule 抽象类,而AbstractLoadBalancerRule 实现了IRule:
AbstractLoadBalancerRule :
public abstract class AbstractLoadBalancerRule implements IRule, IClientConfigAware {
private ILoadBalancer lb;
public AbstractLoadBalancerRule() {
}
public void setLoadBalancer(ILoadBalancer lb) {
this.lb = lb;
}
public ILoadBalancer getLoadBalancer() {
return this.lb;
}
}
综上可以看出,RandomRule继承AbstractLoadBalancerRule重写IRule接口的choose方法,实现负载均衡。那么我们自定义负载均衡算法,只需要仿照RandomRule,继承AbstractLoadBalancerRule,重写 choose(Object key)方法,自定义实现负载均衡规则。
自定义负载均衡算法使用和配置:
MyIRule:
public class MyIRule extends AbstractLoadBalancerRule {
Random rand = new Random();
public RandomRule() {
}
@SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
public Server choose(ILoadBalancer lb, Object key) {
......
......
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
使自定义负载均衡算法起作用,不能像使用Ribbon中默认负载均衡算法一样直接注入容器,需要注意以下几点:
- 自定义的负载均衡算法,不能在SpringBoot启动时扫描到,即自定义的负载均衡类,不能放在启动类的子包或启动类所在包中。
- 定义配置类将自定义的负载均衡算法注入Spring容器中。(配置类也不能被启动类扫描到)
- 启动类上添加注解@RibbonClient(name="微服务名", configuration="装载自定义负载均衡算法的配置类")。
@SpringBootApplication
@EnableEurekaClient
//在启动该微服务的时候就能去加载我们的自定义Ribbon配置类,从而使配置生效
@RibbonClient(name="cloud-provider",configuration=MySelfRuleConfig.class)
public class CloudRibbon{
public static void main(String[] args)
{
SpringApplication.run(CloudRibbon.class, args);
}
}
版权声明:本文为zhoushimiao1990原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。