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客户端所共享,也就是我们达不到特殊化指定的目的了。
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的几个策略:
其中轮询就是默认的策略
修改主启动类
修改主启动类,添加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的时候,就可以实现每台服务器访问五次后,在进行切换