欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Ribbon的负载均衡

程序员文章站 2022-06-22 19:54:22
...

Ribbon 负载均衡

干什么的?

简单的来说就是把用户的请求平摊到多个服务器上,从而达到高可用。

怎么用?

引入ribbon的jar包

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>

添加一个配置类,注入一个负载均衡的策略类

@Configuration
public class MySelfRule {

    @Bean
    public IRule getIRule(){
        return new MyRandomRule();
    }

}

注意:这里MyRandomRule是我自己定义的负载均衡策略类,是模仿RandomRule写的,主要是实现:每台机器访问五次后,在进行切换。
这里有一个坑:
官方文档上指出,这个自定义的类不能放在@ComponentScan所扫描的当前包以及子包下,否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,也就是我们达不到特殊化指定的目的了。

Ribbon的负载均衡

MyRandomRule自定义策略类继承AbstractLoadBalancerRule,ribbon的其他负载均衡策略也是继承该类,故我们可以先照葫芦画瓢,继承一波,然后借鉴一下 RandomRule里面的源码,我们自己改造一下。

/**
 * 每台机器调用五次后,在进行切换服务器
 * @author:hl.yuan
 * @date:2020-08-18
 */
public class MyRandomRule extends AbstractLoadBalancerRule {

    // 总共被调用的次数,目前要求每台被调用5次
    private int total = 0;
    // 当前提供服务的机器号
    private int currentIndex = 0;

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {

    }

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

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

            //private int total = 0; // 总共被调用的次数,目前要求每台被调用5次
            //private int currentIndex = 0; // 当前提供服务的机器号
            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;
    }
}

RandomRule 源码

public class RandomRule extends AbstractLoadBalancerRule {

    /**
     * Randomly choose from all living servers
     */
    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
    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;
            }

            int index = chooseRandomInt(serverCount);
            server = upList.get(index);

            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;

    }

    protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount);
    }

	@Override
	public Server choose(Object key) {
		return choose(getLoadBalancer(), key);
	}

	@Override
	public void initWithNiwsConfig(IClientConfig clientConfig) {
		// TODO Auto-generated method stub
		
	}
}

其实可以看到这里我其实就是更改了源码的里的chooseRandomInt方法,替换成了我自己的逻辑。在这里,建议大家也可以去看下ribbon的负载均衡策略的源码,应该是可以有收获的。
在这里简单的介绍一下,ribbon的几个策略:

Ribbon的负载均衡

其中轮询就是默认的策略

修改主启动类

修改主启动类,添加RibbonClient注解启动。

@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "CLOUD-PROVIDER-PAYMENT", configuration = MySelfRule.class)
public class SpringBootApp80 {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootApp80.class,args);
    }
}

测试

最后启动我们相关服务,当客户端调用restTemplate的时候,就可以实现每台服务器访问五次后,在进行切换

相关标签: springcloud ribbon