Ribbon負載均衡器
- Ribbon負載均衡器
1、Ribbon負載均衡器
- Ribbon的負載均衡接口,定義了服務器的操作,主要是用於進行服務器的選擇
- 在《Spring Cloud_6_負載均衡框架Ribbon》的案例中,客戶端使用了RestClient類,在發送請求時,會使用負載均衡器(ILoadBalancer)接口,根據特定的邏輯來選擇服務器,服務器列表可以使用listOfServers進行配置,也可以使用動態更新機制
- 試用負載均衡器
1.1、修改測試類
package com.atm.cloud;
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 MyChoseRESTClient {
public static void main(String[] args) {
// 創建負載均衡器
ILoadBalancer iLoadBalancer = new BaseLoadBalancer();
// 添加服務器
List<Server> serverList = new ArrayList<Server>();
serverList.add(new Server("localhost", 8080));
serverList.add(new Server("localhost", 8081));
iLoadBalancer.addServers(serverList);
//進行6次服務器選擇
for (int i = 0; i < 6; i++) {
Server server=iLoadBalancer.chooseServer(null);
System.out.println(server);
}
}
}
- 代碼中使用了BaseLoadBalancer這個負載均衡器,將兩個服務器對象加入到負載均衡器中,再調用了6次chooseServer方法
- 根據結果可以判定,選擇服務器的邏輯是一致的,在默認情況下,會使用RoundRobinRule的規則邏輯
1.2、自定義負載規則
- 由前面小節可知,選擇那個服務器進行請求處理,由ILoadBalancer接口的chooserServer方法決sing,而在BaseLoadBalancer類中,則使用IRule接口的choose方法來決定選擇哪一個服務器對象
- 如果想自定義負載均衡規定,可以編寫一個IRule接口的實現類,實現自己的負載規定
package com.atm.cloud;
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 {
ILoadBalancer ibBalancer;
public MyRule() {
}
public MyRule(ILoadBalancer iLoadBalancer) {
this.ibBalancer = iLoadBalancer;
}
public Server choose(Object key) {
// 獲取全部的服務器
List<Server> servers = ibBalancer.getAllServers();
/**
Random random=new Random();
int randNum=random.nextInt(10);
if(randNum>7){
getServerByPort(servers, 8081);
}
**/
// 至返回第一個Server對象
//return getServerByPort(servers, 8080);
return servers.get(0);
}
public Server getServerByPort(List<Server> servers,int port){
for (Server server : servers) {
if(server.getPort()==port){
return server;
}
}
return null;
}
public ILoadBalancer getLoadBalancer() {
return this.ibBalancer;
}
public void setLoadBalancer(ILoadBalancer iLoadBalancer) {
this.ibBalancer = iLoadBalancer;
}
}
- 在自定義規則類中,實現了choose方法,調用了ILoadBalancer的gerAllServers方法返回全部的服務器,爲了簡單起見,本例只返回第一個服務器
- 爲了能在負載均衡器中使用自定義的規則,需要修改選擇服務器的代碼
package com.atm.cloud;
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 MyChoseRESTClient {
public static void main(String[] args) {
// 創建負載均衡器
//ILoadBalancer iLoadBalancer = new BaseLoadBalancer();
BaseLoadBalancer iLoadBalancer=new BaseLoadBalancer();
//設置自定義的負載規則
iLoadBalancer.setRule(new MyRule(iLoadBalancer));
// 添加服務器
List<Server> serverList = new ArrayList<Server>();
serverList.add(new Server("localhost", 8080));
serverList.add(new Server("localhost", 8081));
iLoadBalancer.addServers(serverList);
//進行6次服務器選擇
for (int i = 0; i < 6; i++) {
Server server=iLoadBalancer.chooseServer(null);
System.out.println(server);
}
}
}
- 可以看到,請求6次所得到的服務器均爲8080
- 以上是直接使用編碼方式來設置負載規則,可以使用配置的方式來完成這些工作
- 修改Ribbon的配置,讓請求的客戶端,使用我們定義的負載規則
package com.atm.cloud;
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 MyRESTClient {
public static void main(String[] args) {
// 設置請求的服務器
ConfigurationManager.getConfigInstance().setProperty(
"my-client.ribbon.listOfServers",
"localhost:8080,localhost:8081");
// *****配置規則處理類
ConfigurationManager.getConfigInstance().setProperty(
"my-client.ribbon.NFLoadBalancerRuleClassName",
MyRule.class.getName());
// 獲取REST請求客戶端
RestClient client = (RestClient) ClientFactory
.getNamedClient("my-client");
// 創建請求實例
HttpRequest request = HttpRequest.newBuilder().uri("/person/1").build();
// 發送6次請求到服務器中
for (int i = 0; i < 6; i++) {
try {
HttpResponse response = client.executeWithLoadBalancer(request);
String result = response.getEntity(String.class);
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
- 請求客戶端中,基本與前面張傑的客戶端基本一致,只是加入了“my-client.ribbon.NFLoadBalancerRuleClassName”屬性,設置了自定義規則處理類爲MyRule,這個配置項同樣可以在配置文件中使用,包括SpringCloud的配置文件等
- 在實際環境中,如果要實現自定義的負載規則,可能還需要結合各種因素:具體業務的發生時間、服務器性能等
1.3、Ribbon自帶的負載規則
Ribbon提供了若干個內置的負載規則,使用者完全可以直接使用
- RoundRobinRule:系統默認的規則,通過簡單的輪詢服務列表來選擇服務器,其他的規則在很多情況下,仍然使用RoundRobinRule
AvailablilityFilteringRule:該各種會忽略以下服務器
無法連接的服務器:在默認情況下,如果3次連接失敗,該服務器將會被置爲“短路”的狀態,該狀態將持續30秒,如果再次連接失敗,“短路”狀態的持續時間將會以幾何級增加。可以通過修改niws.loadbalance..connerctionFailureCountThreshold屬性來配置連接失敗的次數
併發數過高的服務器:如果連接到該服務器的併發數過高,也會被這個規則忽略,可以通過修改.ribbon.ActiveConnectionLimit屬性來設定最高併發數WeightedResponseTimeRule:爲每個服務器賦予一個權重值,服務器的響應時間越長,該權重值就越少,這個規則會隨機選擇服務器,這個權重值有可以能會決定服務器的選擇
- ZoneAvoidanceRule:該規則以區域、可用服務器爲基礎,進行服務器選擇。使用Zone對服務器進行分類,可以理解爲機架或者機房
- BestAvailiableRule:忽略“短路”的服務器,並選擇併發數較低的服務器
- RandomRule:隨機選擇可用服務器
- RetryRule:含有重試的選擇邏輯,如果使用RoundRobinRule
以上提供的負載規則,基本上可以滿足大部分的需求
1.4、Ping機制
- 在負載均衡器中,提供了Ping的機制,每隔一段時間,會去Ping服務器,判斷服務器是否存活
- 該工作由IPing接口的實現類負責,如果單獨使用Ribbon,在默認情況下,不會激活Ping機制,默認的實現類爲DummyPing
package com.atm.cloud;
import java.util.ArrayList;
import java.util.List;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.PingUrl;
import com.netflix.loadbalancer.Server;
public class MyTestPingUrl {
public static void main(String[] args) throws InterruptedException {
// 創建負載均衡器
BaseLoadBalancer lb = new BaseLoadBalancer();
// 添加服務器
List<Server> servers = new ArrayList<Server>();
// 8080 端口連接正常
servers.add(new Server("localhost", 8080));
// 一個不存在的端口
servers.add(new Server("localhost", 8888));
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());
}
}
}
- 使用了代碼的方法來設置負載均衡器使用PingUrl,設置了每隔2秒,就向兩個服務器請求
- PingUrl實際是使用的是HttpClient
- 除了在代碼中配置IPing類外,還可以在配置中設置IPing實現類
package com.atm.cloud;
import java.util.List;
import com.netflix.client.ClientFactory;
import com.netflix.config.ConfigurationManager;
import com.netflix.loadbalancer.PingUrl;
import com.netflix.loadbalancer.Server;
import com.netflix.niws.client.http.RestClient;
public class MyPingConfig {
public static void main(String[] args) throws InterruptedException {
// 設置請求的服務器
ConfigurationManager.getConfigInstance().setProperty(
"my-client.ribbon.listOfServers",
"localhost:8080,localhost:8888");
// 配置 Ping 處理類
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);
// 獲取全部服務器
List<Server> servers = client.getLoadBalancer().getAllServers();
System.out.println(servers.size());
// 輸出狀態
for (Server s : servers) {
System.out.println(s.getHostPort() + " 狀態:" + s.isAlive());
}
}
}
- my-client.ribbon.NFLoadBalancerPingClassName:配置 IPing 的實現類
- my-client.ribbon.NFLoadBalancerPingInterval:配置 Ping 操作的時間間隔。
- 以上兩個配置,同樣可以使用在配置文件中
1.5、自定義Ping
- 實現自定義Ping較爲簡單,先實現IPing接口,再通過配置來設定具體的Ping實現類
package com.atm.cloud;
import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.Server;
public class MyPing implements IPing{
public boolean isAlive(Server server) {
System.out.println("這是自定義 Ping 實現類:" + server.getHostPort());
return true;
}
}
- 要使用自定義的Ping類,通 過 修 改client.nameSpace.NFLoadBalancerPingClassName 配置即可
1.6、其他配置
- NFLoadBalancerClassName:指定負載均衡器的實現類,可利用該配置,實現自己的負載均衡器。
NIWSServerListClassName:服務器列表處理類,用來維護服務器列表,Ribbon
已經實現動態服務器列表。NIWSServerListFilterClassName:用於處理服務器列表攔截。