1. 程式人生 > >SpringCloud 之客戶端負載均衡策略

SpringCloud 之客戶端負載均衡策略

一、負載均衡介紹

負載均衡(Load Balance): 建立在現有網路結構之上,它提供了一種廉價有效透明的方法擴充套件網路裝置和伺服器的頻寬、增加吞吐量、加強網路資料處理能力、提高網路的靈活性和可用性。其意思就是分攤到多個操作單元上進行執行,例如Web伺服器、FTP伺服器、企業關鍵應用伺服器和其它關鍵任務伺服器等,從而共同完成工作任務。

1、服務端負載均衡:客戶端請求到負載均衡伺服器,負載均衡伺服器根據自身的演算法將該請求轉給某臺真正提供業務的伺服器,該伺服器將響應資料給負載均衡伺服器,負載均衡伺服器最後將資料返回給客服端。(nginx)

2、客服端負載均衡:基於客戶端的負載均衡,簡單的說就是在客戶端程式裡面,自己設定一個排程演算法,在向伺服器發起請求的時候,先執行排程演算法計算出向哪臺伺服器發起請求,然後再發起請求給伺服器。

二、負載均衡策略介紹

(1) AbstractLoadBalancerRule

AbstractLoadBalancerRule是一個抽象類,裡邊主要定義了一個ILoadBalancer,定義它的目的主要是輔助負責均衡策略選取合適的服務端例項。

(2) RandomRule

該負載均衡策略就是隨機選擇一個服務例項,看原始碼我們知道,在RandomRule的無參構造方法中初始化了一個Random物件,然後在它重寫的choose方法又呼叫了choose(ILoadBalancer lb, Object key)這個過載的choose方法,在這個過載的choose方法中,每次利用random物件生成一個不大於服務例項總數的隨機數,並將該數作為下標所以獲取一個服務例項。

(3) RoundRobinRule

RoundRobinRule這種負載均衡策略叫做線性負載均衡策略,也就是我們在上文所說的BaseLoadBalancer負載均衡器中預設採用的負載均衡策略。這個類的choose(ILoadBalancer lb, Object key)函式整體邏輯是這樣的:開啟一個計數器count,在while迴圈中遍歷服務清單,獲取清單之前先通過incrementAndGetModulo方法獲取一個下標,這個下標是一個不斷自增長的數先加1然後和服務清單總數取模之後獲取到的(所以這個下標從來不會越界),拿著下標再去服務清單列表中取服務,每次迴圈計數器都會加1,如果連續10次都沒有取到服務,則會報一個警告No available alive servers after 10 tries from load balancer: XXXX

(4) RetryRule

看名字就知道這種負載均衡策略帶有重試功能。首先RetryRule中又定義了一個subRule,它的實現類是RoundRobinRule,然後在RetryRule的choose(ILoadBalancer lb, Object key)方法中,每次還是採用RoundRobinRule中的choose規則來選擇一個服務例項,如果選到的例項正常就返回,如果選擇的服務例項為null或者已經失效,則在失效時間deadline之前不斷的進行重試(重試時獲取服務的策略還是RoundRobinRule中定義的策略),如果超過了deadline還是沒取到則會返回一個null。

(5) WeightedResponseTimeRule

WeightedResponseTimeRule是RoundRobinRule的一個子類,在WeightedResponseTimeRule中對RoundRobinRule的功能進行了擴充套件,WeightedResponseTimeRule中會根據每一個例項的執行情況來給計算出該例項的一個權重,然後在挑選例項的時候則根據權重進行挑選,這樣能夠實現更優的例項呼叫。WeightedResponseTimeRule中有一個名叫DynamicServerWeightTask的定時任務,預設情況下每隔30秒會計算一次各個服務例項的權重,權重的計算規則也很簡單,如果一個服務的平均響應時間越短則權重越大,那麼該服務例項被選中執行任務的概率也就越大。

(6) ClientConfigEnabledRoundRobinRule

ClientConfigEnabledRoundRobinRule選擇策略的實現很簡單,內部定義了RoundRobinRule,choose方法還是採用了RoundRobinRule的choose方法,所以它的選擇策略和RoundRobinRule的選擇策略一致,不贅述。

(7) BestAvailableRule

BestAvailableRule繼承自ClientConfigEnabledRoundRobinRule,它在ClientConfigEnabledRoundRobinRule的基礎上主要增加了根據loadBalancerStats中儲存的服務例項的狀態資訊來過濾掉失效的服務例項的功能,然後順便找出併發請求最小的服務例項來使用。然而loadBalancerStats有可能為null,如果loadBalancerStats為null,則BestAvailableRule將採用它的父類即ClientConfigEnabledRoundRobinRule的服務選取策略(線性輪詢)。

(8) PredicateBasedRule

PredicateBasedRule是ClientConfigEnabledRoundRobinRule的一個子類,它先通過內部定義的一個過濾器過濾出一部分服務例項清單,然後再採用線性輪詢的方式從過濾出來的結果中選取一個服務例項。

(9) ZoneAvoidanceRule

ZoneAvoidanceRule是PredicateBasedRule的一個實現類,只不過這裡多一個過濾條件,ZoneAvoidanceRule中的過濾條件是以ZoneAvoidancePredicate為主過濾條件和以AvailabilityPredicate為次過濾條件組成的一個叫做CompositePredicate的組合過濾條件,過濾成功之後,繼續採用線性輪詢的方式從過濾結果中選擇一個出來。使用ZoneAvoidancePredicate和AvailabilityPredicate來判斷是否選擇某個server,前一個判斷判定一個zone的執行效能是否可用,剔除不可用的zone(的所有server),AvailabilityPredicate用於過濾掉連線數過多的Server。

三、使用Ribbon實現負載均衡

Ribbon 工作分為2步:

  1.選擇Eureka Server,優先選擇在同一Zone且負載較少的Server.

  2.根據使用者指定的策略,在從Server取到的服務註冊列表中選擇一個地址。

策略包括:輪詢,隨機,響應時間加權。

關鍵程式碼如下:

1.主要是在RestTemplate上加入了@LoadBalanced,讓restTemplate具備Ribbon負載均衡的能力。

啟動類:

  1. package com.dynamic.cloud;  
  2. import org.springframework.boot.SpringApplication;  
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;  
  4. import org.springframework.cloud.client.loadbalancer.LoadBalanced;  
  5. import org.springframework.cloud.netflix.eureka.EnableEurekaClient;  
  6. import org.springframework.context.annotation.Bean;  
  7. import org.springframework.web.client.RestTemplate;  
  8. @SpringBootApplication  
  9. @EnableEurekaClient  
  10. public class ComsumerMovieRibbonApplication {  
  11.     @Bean  
  12.     @LoadBalanced//讓restTemplate具備Ribbon負載均衡的能力。  
  13.     public RestTemplate restTemplate()  
  14.     {  
  15.         return new RestTemplate();  
  16.     }  
  17.     public static void main(String[] args) {  
  18.         SpringApplication.run(ComsumerMovieRibbonApplication.class, args);  
  19.     }  
  20. }  


2.修改Controller中的微服務地址,修改硬編碼為Eureka上註冊的服務的ServicId,即使用者微服務的application.name;

  1. package com.dynamic.cloud.controller;  
  2. import org.springframework.beans.factory.annotation.Autowired;  
  3. import org.springframework.beans.factory.annotation.Value;  
  4. import org.springframework.web.bind.annotation.GetMapping;  
  5. import org.springframework.web.bind.annotation.PathVariable;  
  6. import org.springframework.web.bind.annotation.RestController;  
  7. import org.springframework.web.client.RestTemplate;  
  8. import com.dynamic.cloud.entity.User;  
  9. @RestController  
  10. public class MovieController {  
  11.     @Autowired  
  12.     private RestTemplate restTemplate;  
  13.     @GetMapping("/movie/{id}")  
  14.     public User findById(@PathVariable Long id)  
  15.     {  
  16.         //http://localhost:7900/simple/  
  17.         //VIP Virtual IP:虛擬IP,使用的是服務提供者的ServiceId,也就是application.name  
  18.         //HAProxy HeartBeat  
  19.         //microservice-provider-user:7900  
  20.         return this.restTemplate.getForObject("http://microservice-provider-user/simple/"+id, User.class);  
  21.     }  
  22. }  


3.application.yml

  1. server:  
  2.   port: 7902  
  3. spring:  
  4.   application:  
  5.     name: microservice-comsumer-movie-ribbon  
  6. eureka:  
  7.   client:  
  8.     serviceUrl:  
  9.       defaultZone: http://user:[email protected]:8761/eureka  
  10.   instance:   
  11.     prefer-ip-address: true  
  12.     instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}  


啟動Eureka,電影微服務,2個使用者微服務。

  

實現了客戶端負載均衡。