您好,登錄后才能下訂單哦!
簡(jiǎn)介
我們繼續(xù)以之前博客的代碼為基礎(chǔ),增加Ribbon組件來(lái)提供客戶端負(fù)載均衡。負(fù)載均衡是實(shí)現(xiàn)高并發(fā)、高性能、可伸縮服務(wù)的重要組成部分,它可以把請(qǐng)求分散到一個(gè)集群中不同的服務(wù)器中,以減輕每個(gè)服務(wù)器的負(fù)擔(dān)。客戶端負(fù)載均衡是運(yùn)行在客戶端程序中的,如我們的web項(xiàng)目,然后通過(guò)獲取集群的IP地址列表,隨機(jī)選擇一個(gè)server發(fā)送請(qǐng)求。相對(duì)于服務(wù)端負(fù)載均衡來(lái)說(shuō),它不需要消耗服務(wù)器的資源。
基礎(chǔ)環(huán)境
Git:項(xiàng)目源碼
更新配置
我們這次需要在本地啟動(dòng)兩個(gè)產(chǎn)品服務(wù)程序,用來(lái)驗(yàn)證負(fù)載均衡,所以需要為第二個(gè)程序提供不同的端口。Spring Cloud配置服務(wù)中心的配置默認(rèn)會(huì)覆蓋本地系統(tǒng)環(huán)境變量,而我們需要通過(guò)系統(tǒng)環(huán)境變量來(lái)設(shè)置產(chǎn)品服務(wù)的端口,所以需要在配置中心git倉(cāng)庫(kù)中修改產(chǎn)品服務(wù)的配置文件product-service.yml
server: port: 8081 spring: cloud: config: allow-override: true override-system-properties: false
allow-override的默認(rèn)值即為true,寫出它來(lái)是想作說(shuō)明,它的意思是允許遠(yuǎn)程配置中心的配置項(xiàng)覆蓋本地的配置,并不是說(shuō)允許本地的配置去覆蓋遠(yuǎn)程的配置。當(dāng)然我們可以把它設(shè)置成false,但是為了提供更精確的覆蓋規(guī)則,這里保留了默認(rèn)值。
我們添加了override-system-properties=false,即雖然遠(yuǎn)程配置中心的配置文件可以覆蓋本地的配置,但是不要覆蓋本地系統(tǒng)變量。修改完成后提交到git倉(cāng)庫(kù)。
另外,在productService項(xiàng)目的ProductController中添加一些log,用來(lái)驗(yàn)證負(fù)載均衡是否生效:
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; @RestController public 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") @SpringBootApplication public 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")注解,用來(lái)標(biāo)記此項(xiàng)目為Ribbon負(fù)載均衡的客戶端,它需要選擇產(chǎn)品服務(wù)集群中其中的一臺(tái)來(lái)訪問(wèn)所需要的服務(wù),這里的name屬性對(duì)應(yīng)于productService項(xiàng)目中配置的spring.application.name屬性。
@LoadBalanced注解標(biāo)明了RestTemplate會(huì)被配置為自動(dòng)使用Ribbon的LoadBalancerClient來(lái)選擇服務(wù)的uri并發(fā)送請(qǐng)求。
在我們?cè)赑roductService類中添加如下代碼:
@Service public 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); } }
這里新添加了一個(gè)productListLoadBalanced方法,跟之前的productList方法訪問(wèn)的是同一服務(wù),只不過(guò)是用Ribbon Client去做了負(fù)載均衡,這里的uri的host變成了product-service即要訪問(wèn)的服務(wù)的名字,跟@RibbonClient中配置的name屬性保持一致。最后在我們的ProductController中添加下面的代碼:
@RestController public class ProductController { @Autowired private ProductService productService; @RequestMapping("/products") public String productList() { return productService.productList(); } @RequestMapping("/productslb") public String productListLoadBalanced() { return productService.productListLoadBalanced(); } }
來(lái)創(chuàng)建一個(gè)專門處理/productslb請(qǐng)求的方法,調(diào)用productServie提供負(fù)載均衡的方法。
到這里我們的代碼就完成了,代碼看似簡(jiǎn)單,其實(shí)是所有的配置都使用了默認(rèn)值。Ribbon提供了編程式和配置式兩種方式來(lái)配置Ribbon Client?,F(xiàn)簡(jiǎn)單介紹下,后續(xù)深入Ribbon時(shí)再和大家一起看看如何修改它的配置。Ribbon提供如下配置(左邊是接口,右邊是默認(rèn)實(shí)現(xiàn)):
因?yàn)槲覀冞@個(gè)項(xiàng)目用了Eureka,所以有些配置項(xiàng)和默認(rèn)實(shí)現(xiàn)有所不同,如Eureka使用DiscoveryEnabledNIWSServerList取代ribbonServerList來(lái)獲取在Eureka上注冊(cè)的服務(wù)的列表。下邊有一個(gè)簡(jiǎn)單的Congiguration類,來(lái)自Spring官網(wǎng):
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默認(rèn)不會(huì)發(fā)送Ping檢查server的健康狀態(tài),默認(rèn)均正常,然后IRune默認(rèn)實(shí)現(xiàn)為ZoneAvoidanceRule用來(lái)避免AWS EC2問(wèn)題較多的zone,這在本地測(cè)試環(huán)境來(lái)說(shuō)是用不到的,然后替換成了AvailabilityFilteringRule,這個(gè)可以開(kāi)啟Ribbon自帶的斷路器功能,來(lái)過(guò)濾不正常工作的服務(wù)器。
測(cè)試
首先啟動(dòng)我們的configserver配置中心服務(wù),然后啟動(dòng)registry Eureka注冊(cè)與發(fā)現(xiàn)服務(wù),然后啟動(dòng)兩個(gè)productService,第一個(gè)我們可以正常使用spring-boot:run插件來(lái)啟動(dòng),第二個(gè)我們需要給它提供一個(gè)新的端口,可以用如下命令啟動(dòng):
$ SERVER_PORT=8082 mvn spring-boot:run
最后啟動(dòng)我們的web客戶端項(xiàng)目,訪問(wèn)http://localhost:8080/productslb,然后刷新幾次,會(huì)看到運(yùn)行著productService的兩個(gè)命令行窗口會(huì)隨機(jī)出現(xiàn)我們的log:
Access to /products endpoint
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。