Ribbon IRule接口与自定义负载均衡算法

Ribbon中的内置的负载均衡算法,都实现了IRule接口。因此如果我们要自定时负载均衡算法也要实现IRule接口。

IRule接口:

public interface IRule {
    Server choose(Object var1);    //选择哪个服务处理请求

    void setLoadBalancer(ILoadBalancer var1);    //设置ILoadBalancer 类型的变量信息

    ILoadBalancer getLoadBalancer();     //获取ILoadBalancer 类型的变量信息
}

Ribbon中已经实现了IRule接口的类:这些类都是Ribbon中的负载均衡算法,抽象类除外。

Ribbon IRule接口与自定义负载均衡算法_第1张图片

IRule接口中有两个类型值得注意:Server和ILoadBalancer。Server封装了是注册进Eureka的微服务信息,也就代表注册进Eureka的微服务。而ILoadBalancer是一个接口,用来获取注册进Eureka的全部或部分或某个微服务信息,如下:

public interface ILoadBalancer {
    void addServers(List var1);

    Server chooseServer(Object var1);

    void markServerDown(Server var1);

    /** @deprecated */
    @Deprecated
    List getServerList(boolean var1);

    List getReachableServers();

    List 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 upList = lb.getReachableServers(); //获取所有可用的微服务
                List 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中默认负载均衡算法一样直接注入容器,需要注意以下几点:

  1. 自定义的负载均衡算法,不能在SpringBoot启动时扫描到,即自定义的负载均衡类,不能放在启动类的子包或启动类所在包中。
  2. 定义配置类将自定义的负载均衡算法注入Spring容器中。(配置类也不能被启动类扫描到)
  3. 启动类上添加注解@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);
	}
}

 

你可能感兴趣的:(微服务,Ribbon自定义负载均衡算法,IRule)