簡介
我們繼續以之前博客的代碼為基礎,增加Ribbon組件來提供客戶端負載均衡。負載均衡是實現高並發、高性能、可伸縮服務的重要組成部分,它可以把請求分散到一個集群中不同的服務器中,以減輕每個服務器的負擔。客戶端負載均衡是運行在客戶端程序中的,如我們的web項目,然後通過獲取集群的IP地址列表, 隨機選擇一個server發送請求。相對於服務端負載均衡來說,它不需要消耗服務器的資源。
基礎環境
Git:項目源碼
更新配置
我們這次需要在本地啟動兩個產品服務程序,用來驗證負載均衡,所以需要為第二個程序提供不同的端口。 Spring Cloud配置服務中心的配置默認會覆蓋本地系統環境變量,而我們需要通過系統環境變量來設置產品服務的端口,所以需要在配置中心git倉庫中修改產品服務的配置文件product-service.yml
server: port: 8081spring: cloud: config: allow-override: true override-system-properties: false
allow-override的默認值即為true,寫出它來是想作說明,它的意思是允許遠程配置中心的配置項覆蓋本地的配置,並不是說允許本地的配置去覆蓋遠程的配置。當然我們可以把它設置成false,但是為了提供更精確的覆蓋規則,這裡保留了默認值。
我們添加了override-system-properties=false,即雖然遠程配置中心的配置文件可以覆蓋本地的配置,但是不要覆蓋本地系統變量。修改完成後提交到git倉庫。
另外,在productService項目的ProductController中添加一些log,用來驗證負載均衡是否生效:
package cn.zxuqian.controllers;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class ProductController { private static Logger log = LoggerFactory.getLogger(ProductController.class); @RequestMapping("/products") public String productList() { log.info("Access to /products endpoint"); return "外套,夾克,毛衣,T卹"; }}為web配置Ribbon
首先在pom.xml中添加Ribbon的依賴:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId></dependency>
然後修改Application類,添加如下代碼:
@EnableCircuitBreaker@EnableDiscoveryClient@RibbonClient(name = "product-service")@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean @LoadBalanced public RestTemplate rest(RestTemplateBuilder builder) { return builder.build(); }}這裡用到了@RibbonClient(name = "product-service")註解,用來標記此項目為Ribbon負載均衡的客戶端,它需要選擇產品服務集群中其中的一台來訪問所需要的服務,這裡的name屬性對應於productService項目中配置的spring.application.name屬性。
@LoadBalanced註解標明了RestTemplate會被配置為自動使用Ribbon的LoadBalancerClient來選擇服務的uri並發送請求。
在我們在ProductService類中添加如下代碼:
@Servicepublic class ProductService { private final RestTemplate restTemplate; @Autowired private DiscoveryClient discoveryClient; public ProductService(RestTemplate restTemplate) { this.restTemplate = restTemplate; } @HystrixCommand(fallbackMethod = "backupProductList") public String productList() { List<ServiceInstance> instances = this.discoveryClient.getInstances("product-service"); if(instances != null && instances.size() > 0) { return this.restTemplate.getForObject(instances.get(0).getUri() + "/products", String.class); } return ""; } public String backupProductList() { return "夾克,毛衣"; } public String productListLoadBalanced() { return this.restTemplate.getForObject("http://product-service/products", String.class); }}這里新添加了一個productListLoadBalanced方法,跟之前的productList方法訪問的是同一服務,只不過是用Ribbon Client去做了負載均衡,這裡的uri的host變成了product-service即要訪問的服務的名字,跟@RibbonClient中配置的name屬性保持一致。最後在我們的ProductController中添加下面的代碼:
@RestControllerpublic class ProductController { @Autowired private ProductService productService; @RequestMapping("/products") public String productList() { return productService.productList(); } @RequestMapping("/productslb") public String productListLoadBalanced() { return productService.productListLoadBalanced(); }}來創建一個專門處理/productslb請求的方法,調用productServie提供負載均衡的方法。
到這裡我們的代碼就完成了,代碼看似簡單,其實是所有的配置都使用了默認值。 Ribbon提供了編程式和配置式兩種方式來配置Ribbon Client。現簡單介紹下,後續深入Ribbon時再和大家一起看看如何修改它的配置。 Ribbon提供如下配置(左邊是接口,右邊是默認實現):
因為我們這個項目用了Eureka,所以有些配置項和默認實現有所不同,如Eureka使用DiscoveryEnabledNIWSServerList取代ribbonServerList來獲取在Eureka上註冊的服務的列表。下邊有一個簡單的Congiguration類,來自Spring官網:
public class SayHelloConfiguration { @Autowired IClientConfig ribbonClientConfig; @Bean public IPing ribbonPing(IClientConfig config) { return new PingUrl(); } @Bean public IRule ribbonRule(IClientConfig config) { return new AvailabilityFilteringRule(); }}Ribbon默認不會發送Ping檢查server的健康狀態,默認均正常,然後IRune默認實現為ZoneAvoidanceRule用來避免AWS EC2問題較多的zone,這在本地測試環境來說是用不到的,然後替換成了AvailabilityFilteringRule,這個可以開啟Ribbon自帶的斷路器功能,來過濾不正常工作的服務器。
測試
首先啟動我們的configserver配置中心服務,然後啟動registry Eureka註冊與發現服務,然後啟動兩個productService,第一個我們可以正常使用spring-boot:run插件來啟動,第二個我們需要給它提供一個新的端口,可以用如下命令啟動:
$ SERVER_PORT=8082 mvn spring-boot:run
最後啟動我們的web客戶端項目,訪問http://localhost:8080/productslb,然後刷新幾次,會看到運行著productService的兩個命令行窗口會隨機出現我們的log:
Access to /products endpoint
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。