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

    xiaoxiao2022-07-06  252

    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); } }

     

    最新回复(0)