Ribbon负载均衡器详细介绍(七)
LoadBalancer的简单轮询规则
在上一篇博客中,我们使用Ribbon实现了负载,并且轮询请求了服务,我们就接着分析一下Ribbon里面实现负载均衡的LoadBalancer(负载均衡器),去看看它底层是怎么做的,以及这些请求规则如何配置。
首先拿到我们上一篇博客中的ribbon-client项目,在com.init.springCloud包下新建LoadBalancerTest类,在这个类里面新建一个基础的Ribbon负载均衡器,然后创建一个服务列表,并把服务列表装载到基础负载均衡器里,之后让负载均衡器多次执行选择服务,我们通过输出服务信息查看它的选取规则:
package com.init.springCloud;
import java.util.ArrayList;
import java.util.List;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
public class LoadBalancerTest {
public static void main(String[] args) {
ILoadBalancer loadBalancer = new BaseLoadBalancer();
List<Server> servers = new ArrayList<Server>();
servers.add(new Server("localhost",8082));
servers.add(new Server("localhost",8083));
loadBalancer.addServers(servers);
for(int i=0; i<10; i++){
//参数是负载均衡器可用来确定要返回哪个服务器的对象。置空表示不使用
Server chosedServer = loadBalancer.chooseServer(null);
System.out.println("选择的服务是:"+chosedServer);
}
}
}
运行LoadBalancerTest的main()方法,可以查看到控制台轮询选择了两个服务。
通过跟踪LoadBalancer的chooseServer方法,我们可以查看到负载均衡器默认使用的是RoundRobinRule
自定义负载均衡器的规则
参照上面的RoundRobinRule,我们也实现IRule接口,来创建一个自己的规则,在com.init.springCloud包下新建MyRule类,实现IRule接口,编写一个出现8082端口服务概率为20%的规则类:
package com.init.springCloud;
import java.util.List;
import java.util.Random;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.Server;
public class MyRule implements IRule {
private ILoadBalancer lb;
@Override
public Server choose(Object key) {
Random random = new Random();
Integer num = random.nextInt(10);//在0-9这10个随机数里取值
//获取传输负载均衡器里所有的服务
List<Server> servers = lb.getAllServers();
if(num>7){//返回8082端口服务
return chooseServerByPort(servers,8082);
}
//返回8083端口服务
return chooseServerByPort(servers,8083);
}
private Server chooseServerByPort(List<Server> servers,Integer port){
for (Server server : servers) {
if(server.getPort() == port){
return server;
}
}
return null;
}
@Override
public void setLoadBalancer(ILoadBalancer lb) {
this.lb = lb;
}
@Override
public ILoadBalancer getLoadBalancer() {
return lb;
}
}
之后再创建一个类MyRuleTest,让负载均衡器加载我们新建的规则类,实现我们自己的负载,内容和LoadBalancerTest类大致:
package com.init.springCloud;
import java.util.ArrayList;
import java.util.List;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.Server;
public class MyRuleTest {
public static void main(String[] args) {
BaseLoadBalancer loadBalancer = new BaseLoadBalancer();
MyRule myRule = new MyRule();
loadBalancer.setRule(myRule);
List<Server> servers = new ArrayList<Server>();
servers.add(new Server("localhost",8082));
servers.add(new Server("localhost",8083));
loadBalancer.addServers(servers);
for(int i=0; i<10; i++){
//参数是负载均衡器可用来确定要返回哪个服务器的对象。置空表示不使用
Server chosedServer = loadBalancer.chooseServer(null);
System.out.println("选择的服务是:"+chosedServer);
}
}
}
运行MyRuleTest的main()方法,可以看到负载均衡器选择8082端口的概率就变小了
Ribbon的组件可以用编程方式设置,也可以是客户端配置属性的一部分,并通过反射创建。这些相关的属性在配置文件里面需要以”客户端名称”.”命名空间”.”属性名”的方式实现。Ribbon提供了以下属性的设置:
- NFLoadBalancerClassName 负载均衡器类名称设置
- NFLoadBalancerRuleClassName 规则类名称设置
- NFLoadBalancerPingClassName Ping类名称设置
- NIWSServerListClassName 服务列表类名称设置
- NIWSServerListFilterClassName 服务列表过滤器名称设置
我们为了验证创建的自定义规则能否生效,使用上面的配置方法去修改ribbon-client项目的RibbonTest类,增加一行配置自定义负载均衡器规则的代码,RibbonTest类最新代码:
package com.init.springCloud;
import com.netflix.client.ClientException;
import com.netflix.client.ClientFactory;
import com.netflix.client.http.HttpRequest;
import com.netflix.client.http.HttpResponse;
import com.netflix.config.ConfigurationManager;
import com.netflix.niws.client.http.RestClient;
public class RibbonTest {
public static void main(String[] args) {
//设置要请求的服务器
ConfigurationManager.getConfigInstance().setProperty(
"sample-client.ribbon.listOfServers",
"localhost:8082,localhost:8083");
//配置自定义的负载均衡器规则
ConfigurationManager.getConfigInstance().setProperty(
"sample-client.ribbon.NFLoadBalancerRuleClassName",
MyRule.class.getName());
//设置REST请求客户端
RestClient client = (RestClient) ClientFactory.getNamedClient("sample-client");
//创建请求实例
HttpRequest request = HttpRequest.newBuilder().uri("/search/1").build();
//连续发送10次请求到服务器
for(int i=0; i<10; i++){
try {
HttpResponse response = client.executeWithLoadBalancer(request);
String result = response.getEntity(String.class);
System.out.println("请求结果:"+result);
} catch (ClientException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
之后启动ribbon-server,在控制台键入两个端口8082和8083,运行两个不同的服务实例,再回来运行ribbon-client项目RibbonTest的main()方法,可以看到控制台输出的结果,证明我们配置的规则类成功了。
Ribbon内置的规则
- AvailabilityFilteringRule: 这条规则将跳过被认为是“电路跳闸”的服务器或具有高并发连接数的服务器。
- BestAvailableRule:这个规则会跳过“电路跳闸”的服务器,然后选取一个并发请求数最低的服务。
- PredicateBasedRule:将服务器过滤逻辑委托给{@link AbstractServerPredicate}实例的规则。过滤后,服务器会以循环的方式从过滤列表中返回。
- RandomRule:一种随机分配流量的负载平衡策略。
- RetryRule:在一个配置时间段内当选择server不成功,则一直尝试使用subRule的方式选择一个可用的server。
- RoundRobinRule:这条规则简单地通过轮询来选择服务器。它通常被用作更高级规则的默认规则或后退。
- WeightedResponseTimeRule:对于这个规则,每个服务器根据其平均响应时间给定一个权重。响应时间越长,得到的权重就越小。规则随机选择一个服务器,其中的可能性由服务器的权重决定。
- ZoneAvoidanceRule:使用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server,前一个判断判定一个zone的运行性能是否可用,剔除不可用的zone(的所有server),AvailabilityPredicate用于过滤掉连接数过多的Server。
常用的一些规则我用蓝色字体凸显出来了,其实大部分规则底层使用的都是RoundRobinRule。
最后,大家有什么不懂的或者其他需要交流的内容,也可以进入我的QQ讨论群一起讨论:654331206
Spring Cloud系列:
Spring Cloud服务管理框架Eureka简单示例(三)