持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情
05、Ribbon负载均衡机制
负载均衡器
Ribbon 的负载均衡器接口定义了服务器的操作,主要是用于进行服务器选择。在前面 的例子中 客户端使用了 RestClient 在发送请求时,会使用负载均衡器 CILoadBalancer 接口,根据特定的逻辑来选择服务器。 服务器列表可使用 listOfServer 进行配置,也可以 使用动态更新机制。下面使用负载均衡器来选择服务器。
/**
* 使用负载均衡器来选择服务器-- ,在默认情况下,会使用 RoundRobinRule 的规则逻辑
*/
@Test
public void ChoseServerTest() {
//创建负载均衡器
ILoadBalancer lb = new BaseLoadBalancer();
ArrayList<Server> servers = new ArrayList<>();
servers.add(new Server("localhost", 8888));
servers.add(new Server("localhost", 9999));
lb.addServers(servers);
//进行6次服务器选择
for (int i = 0; i < 6; i++) {
// 选择哪个服务器进行请求处理,由 ILoadBalancer 接口的 choose Server 方法决定。
// 而在 BaseLoadBalancer 类中 ,则使用 IRule 接口的 choose 方法来 决定选择哪 个服务器对象
Server server = lb.chooseServer(null);
System.out.println(server);
}
}
自定义负载规则
选择哪个服务器进行请求处理,由 ILoadBalancer 接口的 choose Server 方法决定。而在 BaseLoadBalancer 类中 ,则使用 IRule 接口的 choose 方法来 决定选择哪 个服务器对象 如果想自定义负载均衡规定,可以编写 IRule 接口的 实现类
public class MyRule implements IRule {
private ILoadBalancer lb;
public MyRule() {
}
public MyRule(ILoadBalancer lb) {
this.lb = lb;
}
public Server choose(Object key) {
//在自定义规则类中,实现的 choose 方法调用了 ILoadBalancer getAllServers 方法,
返回全部服务器,为了简单起见,本例只返回第一个服务器。
List<Server> servers = lb.getAllServers();
System.out.println("这是自定义服务器定规则类,输出服务器信息:");
for (Server s : servers) {
System.out.println(" " + s.getHostPort());
}
return servers.get(0);
}
public void setLoadBalancer(ILoadBalancer lb) {
this.lb = lb;
}
public ILoadBalancer getLoadBalancer() {
return this.lb;
}
}
使用自定义的负载规则两种方式:
/**
* 使用自定义的负载规则 -- MyRule 使用 BaseLoadBalancer类中的 IRule 接口的 choose 方法
*/
@Test
public void ChoseServerTest2() {
//创建负载均衡器
BaseLoadBalancer lb = new BaseLoadBalancer();
//设置自定义的负载规则
lb.setRule(new MyRule(lb));
ArrayList<Server> servers = new ArrayList<>();
servers.add(new Server("localhost", 8888));
servers.add(new Server("localhost", 9999));
lb.addServers(servers);
//进行6次服务器选择
for (int i = 0; i < 6; i++) {
//选择哪个服务器进行请求处理,由 ILoadBalancer 接口的 choose Server 方法决定。
// 而在 BaseLoadBalancer 类中 ,则使用 IRule 接口的 choose 方法来 决定选择哪 个服务器对象
Server server = lb.chooseServer(null);
System.out.println(server);
}
}
/**
* 客户端使用了RestClient 在发送请求时,会使用负载均衡器ILoadBalancer接口,根据特定的逻辑来选择服务器。
*
* @throws Exception
*/
@Test
public void RestClientTest() throws Exception {
//ConfigurationManager来配置请求的服务器列表
ConfigurationManager.getConfigInstance().setProperty("my-client.ribbon.listOfServers",
"localhost:9999,localhost:8888");
//配置规则处理类 也可在配置文件中配置
ConfigurationManager.getConfigInstance().setProperty(
"my-client.ribbon.NFLoadBalancerRuleClassName",
MyRule.class.getName());
//获取REST请求的客户端
RestClient client = (RestClient) ClientFactory.getNamedClient("my-client");
//创建请求实例
HttpRequest request = HttpRequest.newBuilder().uri("/person/8").build();
//
for (int i = 0; i < 6; i++) {
HttpResponse response = client.executeWithLoadBalancer(request);
String result = response.getEntity(String.class);
System.out.println(result);
}
}
Ribbon自带的负载规则
- Ribbon提供了若干个内置的负载规则,使用者完全可以直接使用
- RoundRobinRule:系统默认的规则,通过简单的轮询服务列表来选择服务器,其他的规则在很多情况下,仍然使用RoundRobinRule
- AvailablilityFilteringRule:该各种会忽略以下服务器
- 无法连接的服务器:在默认情况下,如果3次连接失败,该服务器将会被置为“短路”的状态,该状态将持续30秒,如果再次连接失败,“短路”状态的持续时间将会以几何级增加。可以通过修改niws.loadbalance..connerctionFailureCountThreshold属性来配置连接失败的次数
- 并发数过高的服务器:如果连接到该服务器的并发数过高,也会被这个规则忽略,可以通过修改.ribbon.ActiveConnectionLimit属性来设定最高并发数
-
WeightedResponseTimeRule:为每个服务器赋予一个权重值,服务器的响应时间越长,该权重值就越少,这个规则会随机选择服务器,这个权重值有可以能会决定服务器的选择
-
ZoneAvoidanceRule:该规则以区域、可用服务器为基础,进行服务器选择。使用Zone对服务器进行分类,可以理解为机架或者机房
-
BestAvailiableRule:忽略“短路”的服务器,并选择并发数较低的服务器
-
RandomRule:随机选择可用服务器
-
RetryRule:含有重试的选择逻辑,如果使用RoundRobinRule
- 以上提供的负载规则,基本上可以满足大部分的需求
ping机制
在负载均衡器中,提供了 Ping 机制,每隔一段时间,会去 Ping 服务器,判断服务器是否存活。 该工作由 !Ping 接口的实现类负责,如果单独使用 Ribbon 在默认情况下,不会激活 Ping 机制,默认的实现类为 DummyPing 代码 使用了另外 IPing 实现类PingUrl
/**
* 使用Ping机制 ****** 不知道为嘛 在Earue Server 注册过的服务器访问不通 ,其它可以
*/
@Test
public void TestPingUrl() throws InterruptedException {
//创建负载均衡器
BaseLoadBalancer lb = new BaseLoadBalancer();
ArrayList<Server> servers = new ArrayList<>();
servers.add(new Server("localhost", 8888));
servers.add(new Server("localhost", 8762));
lb.addServers(servers);
//设置 IPing 实现类
lb.setPing(new PingUrl());
//设置 Ping 时间间隔为2秒
lb.setPingInterval(2);
Thread.sleep(6000);
for (Server s : lb.getAllServers()) {
System.out.println(s.getHostPort() + "状态:" + s.isAlive());
}
}
在配置中设置IPing实现类:
/**
* 在配置中设置Iping实现类 也可以使用在配置文件中 ***** 在注册中心注册的两个节点不知道为什么也访问不通
*
* @throws Exception
*/
@Test
public void RestPingUrlConfig() throws Exception {
//ConfigurationManager来配置请求的服务器列表
ConfigurationManager.getConfigInstance().setProperty("my-client.ribbon.listOfServers",
"localhost:8761,localhost:8888");
//配置IPing处理类
ConfigurationManager.getConfigInstance().setProperty(
"my-client.ribbon.NFLoadBalancerPingClassName",
PingUrl.class.getName());
//配置Ping时间间隔
ConfigurationManager.getConfigInstance().setProperty(
"my-client.ribbon.NFLoadBalancerPingInterval",
2);
//获取REST请求的客户端
RestClient client = (RestClient) ClientFactory.getNamedClient("my-client");
Thread.sleep(6000);
for (Server s : client.getLoadBalancer().getAllServers()) {
System.out.println(s.getHostPort() + "状态:" + s.isAlive());
}
}
注意代码中的以下两个配置。
- my-client.ribbon.NFLoadBalancerPingClassName :配置 !Ping 的实现类。
- my-client.ribbon.NFLoadBalancerPinglnterval :配置 Ping 操作的时间间隔。
以上两个配置同样可以使用在配置文件中。
自定义Ping
实现自定义Ping较为简单,先实现IPing接口,再通过配置来设定具体的Ping实现类
/**
* 自定义IPing实现类
*/
public class MyPing implements IPing {
@Override
public boolean isAlive(Server server) {
System.out.println("这是自定义的Ping实现类:"+server.getHostPort());
return true;
}
}
要使用自定义的Ping类,通 过修改client.nameSpace.NFLoadBalancerPingClassName 配置即可
其他配置
NFLoadBalancerClassName:指定负载均衡器的实现类,可利用该配置,实现自己的负载均衡器。 NIWSServerListClassName:服务器列表处理类,用来维护服务器列表,Ribbon 已经实现动态服务器列表。 NIWSServerListFilterClassName:用于处理服务器列表拦截。