在上一篇博客中,我们使用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 servers = new ArrayList();
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 servers = lb.getAllServers();
if(num>7){//返回8082端口服务
return chooseServerByPort(servers,8082);
}
//返回8083端口服务
return chooseServerByPort(servers,8083);
}
private Server chooseServerByPort(List 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 servers = new ArrayList();
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提供了以下属性的设置:
我们为了验证创建的自定义规则能否生效,使用上面的配置方法去修改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()方法,可以看到控制台输出的结果,证明我们配置的规则类成功了。
常用的一些规则我用蓝色字体凸显出来了,其实大部分规则底层使用的都是RoundRobinRule。
源码点击这里
最后,大家有什么不懂的或者其他需要交流的内容,也可以进入我的QQ讨论群一起讨论:654331206
Spring Cloud系列:
Spring Cloud介绍与环境搭建(一)
Spring Boot的简单使用(二)
Spring Cloud服务管理框架Eureka简单示例(三)
Spring Cloud服务管理框架Eureka项目集群(四)
Spring Cloud之Eureka客户端健康检测(五)
Netflix之第一个Ribbon程序(六)
Ribbon负载均衡器详细介绍(七)
Spring Cloud中使用Ribbon(八)
具有负载均衡功能的RestTemplate底层原理(九)
OpenFeign之第一个Feign程序(十)
OpenFeign之feign使用简介(十一)
Spring Cloud中使用Feign(十二)
Netflix之第一个Hystrix程序(十三)
Netflix之Hystrix详细分析(十四)
Spring Cloud中使用Hystrix(十五)
Netflix之第一个Zuul程序(十六)
Spring Cloud集群中使用Zuul(十七)
Netflix之Zuul的进阶应用(十八)
消息驱动之背景概述(十九)
消息中间件之RabbitMQ入门讲解(二十)
消息中间件之Kafka入门讲解(二十一)
Spring Cloud整合RabbitMQ或Kafka消息驱动(二十二)