SpringCloud Ribbon(負載均衡)
1.負載均衡LB
全稱Load Balance,將使用者的請求平攤到多個伺服器上,從而達到系統的HA。
1)集中式LB
在服務消費者和服務提供者之間使用獨立的LB設施,如硬體,由該設施負責把訪問請求通過某種策略轉發至服務提供方。
2)程序內LB
將LB邏輯繼承到服務消費者,消費者從服務註冊中心獲知有哪些地址可用,然後從這些地址中選擇一個合適的來使用。Ribbon屬於程序內LB。
2.Ribbon定義
只使用restTemplate問題是服務的地址是寫死的,不利於維護,沒有進行負載均衡。而Ribbon基於NetFlix Ribbon實現的一套客戶端負載均衡的工具。但它可以結合RestTemplate
3.專案實戰
3.1基礎環境搭建
原始碼:https://github.com/zhongyushi-git/cloud-ribbon-demo.git。
說明:由於Eureka2.0已停止維護,故這裡使用consul作為服務註冊中心,使用RestTemplate進入服務的呼叫,使用Ribbon進行服務的負載均衡。
1)建立一個maven工程名為cloud-ribbon-demo
,刪除src目錄
2)在pom中匯入依賴,對SpringBoot和SpringCloud版本進行鎖定
<properties> <spring.boot.version>2.2.2.RELEASE</spring.boot.version> <spring.cloud.version>Hoxton.SR1</spring.cloud.version> </properties> <!-- 依賴管理,父工程鎖定版本--> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring.boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring.cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
3.2搭建服務提供者
1)新建maven子模組(cloud-provider8001),匯入依賴
<dependencies> <!--web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
2)新建啟動類ProviderMain8001並添加註解
package com.zys.cloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @SpringBootApplication @EnableDiscoveryClient public class ProviderMain8001 { public static void main(String[] args) { SpringApplication.run(ProviderMain8001.class, args); } }
3)配置application.yml
server: port: 8001 spring: application: name: cloud-consul-provider cloud: consul: host: localhost port: 8500 discovery: service-name: ${spring.application.name}
4)新建controller介面
package com.zys.cloud.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/user") public class UserController { @Value("${server.port}") private String port; @GetMapping("/get") public String get() { return "我是服務提供者,埠:" + port; } }
5)啟動服務,可看到已註冊到consul。
6)根據服務提供者ProviderMain8001,再分別建立ProviderMain8002和ProviderMain8003.
3.3搭建服務消費者
1)新建maven子模組(cloud-consumer80),匯入依賴
<dependencies> <!--web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
2)新建啟動類ConsumerMain80並添加註解
package com.zys.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerMain80 {
public static void main(String[] args) {
SpringApplication.run(ConsumerMain80.class, args);
}
}
3)配置application.yml
server:
port: 80
spring:
application:
name: cloud-consul-consumer
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: ${spring.application.name}
4)建立配置類,注入RestTemplate
package com.zys.cloud.config; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class ConfigBean { @Bean @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); } }
要在方法上加@LoadBalanced
,否則在服務呼叫時會報錯。添加註解後,在服務呼叫時,就會根據其負載均衡策略進行服務的負載轉發和請求。
5)新建controller介面
package com.zys.cloud.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("/consumer")
public class UserController {
private final String BASE_URL = "http://cloud-consul-provider";
@Autowired
private RestTemplate restTemplate;
@GetMapping("/get")
public String addUser() {
return restTemplate.getForObject(BASE_URL + "/user/get", String.class);
}
}
在設定請求路徑時,http後面是cloud-consul-provider
,這就指定了要呼叫的服務的名字。這樣方便維護,又達到了負載均衡的效果。
5)啟動服務,可看到已註冊到consul。訪問http://localhost/consumer/get,第一次呼叫的是埠為8001的服務,重新整理一次呼叫的是8002服務,再重新整理一次呼叫的是8003服務,依次輪詢。原因是其按預設的輪詢策略進行負載的。
6)負載分析。雖然全文都在說Ribbon,但卻沒有引入其依賴,又能達到效果,這是為何?原因是在引入引入consul時就其已引入了Ribbon,就無需再次引入。
4.Ribbon負載均衡策略
4.1負載策略說明
Ribbon的核心元件是IRule,它的作用就是根據特定的演算法從服務列表中選擇一個要訪問的服務。下面是Ribbon中定義的幾種策略:
策略 | 描述 |
RandomRule | 隨機 |
RoundRobinRule | 輪詢,按照順序選擇server,是Ribbon預設的策略 |
RetryRule | 重試,在一個配置時間段內,當選擇server不成功,則一直嘗試選擇一個可用的server |
BestAvailableRule | 最低併發,逐個考察server,如果server斷路器開啟,則忽略,再選擇其中併發連結最低的server |
AvailabilityFilteringRule | 可用過濾,過濾掉一直失敗並被標記為circuit tripped的server,過濾掉那些高併發連結的server |
ResponseTimeWeightedRule | 響應時間加權重,根據server的響應時間分配權重,響應時間越長,權重越低,被選擇到的概率也就越低。 |
ZoneAvoidanceRule | 區域權重,綜合判斷server所在區域的效能和server的可用性,輪詢選擇server並且判斷一個AWS Zone的執行效能是否可用,剔除不可用的Zone中的所有server |
4.2切換預設的策略
有時需要切換預設策略時,也很簡單,在服務消費者中進行配置即可。
假設要把輪詢策略改為隨機策略,步驟如下:
1)在配置類中注入RandomRule
@Bean public IRule RandomRule(){ return new RandomRule(); }
截圖如下:
2)重啟服務消費者,進行測試,發現已是隨機呼叫各個服務。
就是這麼簡單,你學廢了嗎?感覺有用的話,給筆者點個贊吧 !