之前的文章中我們簡單介紹了一下微服務系統架構中引入Ribbon負載均衡的集成
接下來我們會系統的介紹一下Ribbon的實現及自定義策略負載均衡
1)項目的基礎結構:
在一個微服務中我們存在一個共有api
一個統一的客戶端(服務消費者)80
服務註冊中心的集羣 eureka
服務的提供者(多個)
Ribbon應用的思維導圖:
Ribbon是一個客戶端實現負載均衡的方案,集成在我們的編碼階段,區別於nginx的不同是不需要搭建服務器來實現
其核心主要爲:
- 獲取註冊中心的服務
- 通過用戶定義的負載均衡的策略選擇服務的提供者(默認採用輪詢策略)
Ribbon的核心策略類爲IRule:其中包含的策略有
後面我們會具體介紹這幾種策略
2)實現Ribbon負載均衡
根據官方描述:
可以使用@RibbonClient
實現Ribbon的負載均衡,但是實現類必須是@Configuration
且不能與主啓動類存在與同一級下,所以我們的客戶端項目結構爲
3)修改負載均衡的策略
@Configuration
public class MyRule {
@Bean
public IRule myIRule(){
return new RandomRule(); //隨機
}
}
4)配置主啓動類使用我們的負載均衡配置
@SpringBootApplication
@EnableEurekaClient
//在啓動時加載我們自定義的負載均衡組件,自定義組件必須是@Configuration,他會替換已有的組件,從而使用我們自定義的負載均衡組件
@RibbonClient(name = "peo_user",configuration = MyRule.class)
public class ConApplication {
public static void main(String[] args) {
SpringApplication.run(ConApplication.class,args);
}
}
至此我們就完成了Ribbon的負載均衡的實現,當然,在實際開發中,IRule提供的負載均衡的策略不一定滿足我們服務器的配置需求,這時候就需要我們實現自定義的負載均衡的算法策略,下面我們就介紹一下Ribbon提供的負載均衡的策略及如何實在自定義的負載均衡策略
上面我們介紹到Ribbon的核心組件是IRule,是所有負載均衡算法的父接口,其下有
- RoundRobinRule :輪詢策略,即依次使用存活的服務
- RandomRule : 隨機策略,每次請求會產生一個隨機的服務提供訪問
- AvailabilityFilteringRule :過濾輪詢策略,他會先過濾掉跳閘、故障、超過併發閾值的服務,對剩餘服務使用輪詢策略
- WeightedResponseTimeRule : 權重策略,根據平均響應時間計算所有服務的權重,響應時間越快服務權重越大被選中的概率越高。剛啓動時,如果統計信息不足,則使用輪詢策略,等信息足夠,切換到 WeightedResponseTimeRule
- RetryRule : 重試,先按照輪詢策略獲取服務,如果獲取失敗則在指定時間內重試,獲取可用服務
- BestAvailableRule :選過濾掉多次訪問故障而處於斷路器跳閘狀態的服務,然後選擇一個併發量最小的服務
- ZoneAvoidanceRule : 符合判斷server所在區域的性能和server的可用性選擇服務
以上的幾種策略都繼承AbstractLoadBalancerRule
下面簡單介紹一下隨機策略的實現源碼,其餘實現大家可自行閱讀源碼
public class RandomRule extends AbstractLoadBalancerRule {
public RandomRule() {
}
@SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
} else {
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) {
return null;
}
int index = this.chooseRandomInt(serverCount);//產生一個範圍隨機數
server = (Server)upList.get(index); //獲得存活的服務
if (server == null) {
Thread.yield();
} else {
if (server.isAlive()) {
return server;
}
server = null;
Thread.yield();
}
}
return server;
}
}
protected int chooseRandomInt(int serverCount) {
return ThreadLocalRandom.current().nextInt(serverCount);
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
通過註解我們可以看出,其實就是實現了一個簡單的算法,通過一個範圍隨機數來指定此次訪問的服務爲哪一個。
重點來了-------
重點來了-------
重點來了-------
既然我們已經瞭解了Ribbon負載均衡的算法實現及原理,那麼我們就可以實現我們自己的負載均衡策略
- 集成
AbstractLoadBalancerRule
- 添加實現方法
- 編寫自己的算法策略
- 依據上面的配置修改爲我們自己的策略
描述:每個服務提供五次訪問,滿五次以後切換到下一個服務,當所有服務都使用完畢後從第一個服務繼續開始,編碼如下
public class MyBalancerRule extends AbstractLoadBalancerRule {
private int total = 0; //服務被調用次數
private int currentIndex = 0; //當前提供服務的服務下標
public MyBalancerRule(){
}
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
/**
* 自定義策略,訪問五次更換服務
*/
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
} else {
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) { //如果不存在服務,返回
return null;
}
if(total < 5){ //服務未被調用五次,可以繼續使用當前服務
server = upList.get(currentIndex); //獲取當前服務
total++; //增加服務調用次數
}else{ //服務已被調用五次,需要更換服務
total = 0; //歸零服務被調用次數
currentIndex++; //下移當前被調用服務下標
if(currentIndex > upList.size())currentIndex = 0; //如果當前下標大於現存的服務個數,則從頭開始
server = upList.get(currentIndex); //獲取當前服務
}
if (server == null) {
Thread.yield();
} else {
if (server.isAlive()) {
return server;
}
server = null;
Thread.yield();
}
}
return server;
}
}
}
@Configuration
public class MyRule {
@Bean
public IRule myIRule(){
return new MyBalancerRule(); //自定義負載均衡策略
}
}
我們也可以使用配置文件來配置:
eureka.client.service-url.defaultZone=http://localhost:7001/eureka/,http://localhost:7002/eureka/
server.port=80
spring.application.name=pro_user
springboot-eureka-clent.ribbon.NFLoadBalancerRuleClassName=com.balance.config.MyBalancerRule
補充知識
在非eureka環境下使用Ribbon
#取消Ribbon使用Eureka
ribbon.eureka.enabled=false
#配置Ribbon能訪問 的微服務節點,多個節點用逗號隔開
microservice-provider-user.ribbon.listOfServers=localhost:7001,localhost:7002