SpringCloud負(fù)載均衡spring-cloud-starter-loadbalancer解讀
簡(jiǎn)述
spring-cloud-starter-loadbalancer 是 Spring Cloud 中的一個(gè)組件,它提供了客戶端負(fù)載均衡的功能。在 Spring Cloud 的早期版本中,Netflix Ribbon 被廣泛用作客戶端負(fù)載均衡器,但隨著時(shí)間推移和 Netflix Ribbon 進(jìn)入維護(hù)模式,Spring Cloud 社區(qū)開始轉(zhuǎn)向更靈活、更易于維護(hù)的替代方案。
spring-cloud-starter-loadbalancer 是基于 Spring 5 的 WebClient 構(gòu)建的,并使用了 Reactor(Spring 5 的反應(yīng)式編程模型的核心庫(kù))來(lái)實(shí)現(xiàn)異步非阻塞的負(fù)載均衡請(qǐng)求。它與 Spring Cloud 的服務(wù)發(fā)現(xiàn)和配置結(jié)合得非常好,可以很容易地與 Eureka、Consul、Nacos 等服務(wù)發(fā)現(xiàn)組件一起使用。
當(dāng)將 spring-cloud-starter-loadbalancer 添加到Spring Boot 應(yīng)用程序中時(shí),可以使用 WebClient.Builder 的 loadBalancer 方法來(lái)創(chuàng)建一個(gè)具有負(fù)載均衡功能的 WebClient 實(shí)例。這個(gè) WebClient 實(shí)例會(huì)自動(dòng)從服務(wù)發(fā)現(xiàn)中獲取服務(wù)實(shí)例列表,并使用內(nèi)置的負(fù)載均衡算法(如輪詢、隨機(jī)等)來(lái)選擇一個(gè)服務(wù)實(shí)例來(lái)發(fā)送請(qǐng)求。
例如,如果正在使用 Eureka 作為服務(wù)發(fā)現(xiàn),并且想要發(fā)送一個(gè) GET 請(qǐng)求到名為 “my-service” 的服務(wù),可以這樣做:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; @Service public class MyServiceClient { @Autowired private WebClient.Builder webClientBuilder; @Bean @LoadBalanced public WebClient.Builder loadBalancedWebClientBuilder() { return WebClient.builder(); } public String getSomethingFromMyService() { // 注意這里我們直接使用了 "my-service" 作為 URI,而不是具體的服務(wù)實(shí)例地址 return webClientBuilder.build() .get() .uri("http://my-service/some-endpoint") .retrieve() .bodyToMono(String.class) .block(); // 注意:block() 方法會(huì)阻塞當(dāng)前線程,通常只在非反應(yīng)式上下文中使用 } }
主要特點(diǎn)
- 基于 WebClient:與 Spring 5 的 WebClient 緊密集成,提供了反應(yīng)式(Reactive)的 HTTP 客戶端功能。
- 服務(wù)發(fā)現(xiàn)集成:與 Spring Cloud 的服務(wù)發(fā)現(xiàn)組件(如 Eureka、Consul、Nacos 等)集成,可以自動(dòng)獲取服務(wù)實(shí)例列表。
- 內(nèi)置負(fù)載均衡算法:提供了內(nèi)置的負(fù)載均衡算法,如輪詢(Round Robin)、隨機(jī)(Random)等。
- 反應(yīng)式編程:支持反應(yīng)式編程模型,允許非阻塞的 I/O 操作和異步處理。
- 靈活性:與 Ribbon 相比,提供了更多的靈活性和擴(kuò)展性,可以更容易地定制負(fù)載均衡行為。
- 與 Spring Cloud Gateway 集成:與 Spring Cloud Gateway 緊密集成,為其提供了負(fù)載均衡功能。
使用
- 添加依賴:在 Maven 或 Gradle 項(xiàng)目中添加 spring-cloud-starter-loadbalancer 依賴。
<!-- SpringCloud Loadbalancer --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency>
- 配置 WebClient:使用 @LoadBalanced 注解來(lái)標(biāo)記一個(gè) WebClient.Builder Bean,以便將其配置為支持負(fù)載均衡。
- 發(fā)送請(qǐng)求:通過(guò) WebClient 發(fā)送請(qǐng)求時(shí),使用服務(wù)名稱(而不是具體的服務(wù)實(shí)例地址)作為 URI 的主機(jī)部分。
- 自定義負(fù)載均衡算法:如果需要,可以自定義負(fù)載均衡算法,并通過(guò)配置或編程方式將其應(yīng)用到 WebClient 上。
注意事項(xiàng):
- 阻塞調(diào)用:雖然 WebClient 是反應(yīng)式的,但在某些情況下(如與同步代碼交互時(shí)),可能需要使用 block() 方法來(lái)阻塞當(dāng)前線程并等待響應(yīng)。但應(yīng)盡量避免在反應(yīng)式上下文中使用 block()。
- 配置:負(fù)載均衡器的行為可以通過(guò)配置進(jìn)行定制,包括選擇負(fù)載均衡算法、設(shè)置超時(shí)時(shí)間等。
- 服務(wù)發(fā)現(xiàn):確保應(yīng)用程序已經(jīng)正確配置了服務(wù)發(fā)現(xiàn)組件(如 Eureka、Consul 等),以便 spring-cloud-starter-loadbalancer 能夠獲取服務(wù)實(shí)例列表。
- 版本兼容性:注意 spring-cloud-starter-loadbalancer 與其他 Spring Cloud 組件的版本兼容性,確保它們能夠協(xié)同工作。
負(fù)載均衡算法
1. 輪詢負(fù)載均衡策略(Round Robin)
- 描述:這是默認(rèn)的負(fù)載均衡策略,它會(huì)按照順序依次將請(qǐng)求發(fā)送到服務(wù)實(shí)例列表中的每個(gè)服務(wù)實(shí)例。
- 特點(diǎn):
- 簡(jiǎn)單易實(shí)現(xiàn)。
- 每個(gè)服務(wù)實(shí)例接收到的請(qǐng)求數(shù)量大致相等(在理想情況下)。
- 不考慮服務(wù)實(shí)例的當(dāng)前負(fù)載狀態(tài)或性能。
2. 隨機(jī)負(fù)載均衡策略(Random)
- 描述:該策略會(huì)隨機(jī)選擇一個(gè)服務(wù)實(shí)例來(lái)發(fā)送請(qǐng)求。
- 特點(diǎn):
- 在多次請(qǐng)求中,每個(gè)服務(wù)實(shí)例都有可能被選中。
- 與輪詢策略相比,它增加了隨機(jī)性,但每個(gè)服務(wù)實(shí)例接收到的請(qǐng)求數(shù)量可能不均等。
- 同樣不考慮服務(wù)實(shí)例的當(dāng)前負(fù)載狀態(tài)或性能。
3. 自定義負(fù)載均衡策略
- 描述:除了內(nèi)置的負(fù)載均衡策略外,spring-cloud-starter-loadbalancer 還支持自定義負(fù)載均衡策略。
- 特點(diǎn):
- 開發(fā)者可以根據(jù)實(shí)際需求實(shí)現(xiàn)自己的負(fù)載均衡算法。
- 可以考慮服務(wù)實(shí)例的當(dāng)前負(fù)載狀態(tài)、性能、地理位置等多種因素來(lái)做出決策。
- 提供了更高的靈活性和定制性。
4. Nacos 權(quán)重負(fù)載均衡器
- 描述:當(dāng)與 Nacos 服務(wù)發(fā)現(xiàn)組件一起使用時(shí),可以使用 Nacos 提供的權(quán)重負(fù)載均衡器。
- 特點(diǎn):
- 服務(wù)實(shí)例可以配置權(quán)重值,權(quán)重值越高的實(shí)例接收到的請(qǐng)求越多。
- 權(quán)重值可以根據(jù)服務(wù)實(shí)例的性能、資源使用情況等因素進(jìn)行動(dòng)態(tài)調(diào)整。
- 提供了更細(xì)粒度的控制,可以根據(jù)實(shí)際需求進(jìn)行靈活配置。
5. 自定義算法
通過(guò)實(shí)現(xiàn)自定義的 ReactorLoadBalancer 來(lái)定義自己的負(fù)載均衡算法。
- 定義自定義的負(fù)載均衡器:需要實(shí)現(xiàn) ReactorLoadBalancer 接口或擴(kuò)展現(xiàn)有的實(shí)現(xiàn)(如 RoundRobinLoadBalancer)。
- 實(shí)現(xiàn) choose 方法:這是負(fù)載均衡算法的核心,它接收一個(gè)請(qǐng)求(通常是一個(gè) Request 對(duì)象)和一個(gè)服務(wù)實(shí)例列表(ServiceInstanceListSupplier),并返回一個(gè) Mono,表示選定的服務(wù)實(shí)例。
- 配置自定義的負(fù)載均衡器:需要將自定義的負(fù)載均衡器配置為 Spring Cloud 的默認(rèn)負(fù)載均衡器。這通常是通過(guò)注冊(cè)一個(gè) ReactorLoadBalancer 的 Bean 來(lái)完成的。
示例:
import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.DefaultRequest; import org.springframework.cloud.client.loadbalancer.ReactiveLoadBalancer; import org.springframework.cloud.client.loadbalancer.ReactiveLoadBalancerFactory; import org.springframework.cloud.client.ServiceInstanceChooser; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import reactor.core.publisher.Mono; import java.util.List; @Configuration public class CustomLoadBalancerConfig { @Bean public ReactiveLoadBalancer<ServiceInstance> customLoadBalancer( ReactiveLoadBalancerFactory<ServiceInstance> factory, ObjectProvider<List<ServiceInstance>> serviceInstances) { return new ReactiveLoadBalancer<ServiceInstance>() { @Override public Mono<Response<ServiceInstance>> choose(Request request) { // 這里是自定義的負(fù)載均衡算法實(shí)現(xiàn) // 例如,我們可以簡(jiǎn)單地返回服務(wù)實(shí)例列表中的第一個(gè)實(shí)例 return Mono.justOrEmpty(serviceInstances.getIfAvailable()) .flatMapMany(List::stream) .firstElement() // 或者可以實(shí)現(xiàn)自己的選擇邏輯 .map(Response::just); } // 其他必要的方法(如 recordStats, filter, etc.)可以根據(jù)需要進(jìn)行實(shí)現(xiàn) }; } // 如果想要為特定的服務(wù)配置自定義的負(fù)載均衡器, // 可以通過(guò) ServiceId 來(lái)區(qū)分并返回不同的 ReactiveLoadBalancer 實(shí)例 // 例如,public ReactiveLoadBalancer<ServiceInstance> customLoadBalancerForServiceX(...) {...} }
spring-cloud-starter-loadbalancer 提供了多種負(fù)載均衡算法,包括輪詢、隨機(jī)和自定義策略等。
這些算法可以根據(jù)實(shí)際需求進(jìn)行選擇和配置,以滿足不同的負(fù)載均衡需求。同時(shí),與 Nacos 服務(wù)發(fā)現(xiàn)組件的集成還提供了權(quán)重負(fù)載均衡器的功能,進(jìn)一步增加了負(fù)載均衡的靈活性和可定制性。
開發(fā)者可以根據(jù)自己的業(yè)務(wù)場(chǎng)景和需求選擇適合的負(fù)載均衡算法,并對(duì)其進(jìn)行適當(dāng)?shù)呐渲煤蛢?yōu)化,以實(shí)現(xiàn)更高效、更可靠的微服務(wù)調(diào)用。
反應(yīng)式編程
從 Spring Cloud Greenwich 版本開始,Spring Cloud 引入了對(duì) Project Reactor 的支持,并將負(fù)載均衡器從傳統(tǒng)的阻塞式(基于 Ribbon)轉(zhuǎn)變?yōu)榉磻?yīng)式(基于 spring-cloud-starter-loadbalancer)。
反應(yīng)式編程是一種異步、非阻塞的編程范式,它使用數(shù)據(jù)流(streams)和變化傳播(propagation of change)來(lái)處理數(shù)據(jù)。在反應(yīng)式編程中,數(shù)據(jù)不是通過(guò)傳統(tǒng)的調(diào)用和返回機(jī)制來(lái)傳遞的,而是通過(guò)異步數(shù)據(jù)流在組件之間傳遞。
在 spring-cloud-starter-loadbalancer 中,反應(yīng)式編程主要體現(xiàn)在以下幾個(gè)方面:
- 非阻塞調(diào)用:與傳統(tǒng)的基于 Ribbon 的阻塞式負(fù)載均衡器不同,spring-cloud-starter-loadbalancer 使用反應(yīng)式編程模型來(lái)執(zhí)行非阻塞的負(fù)載均衡請(qǐng)求。這意味著它不會(huì)阻塞線程等待響應(yīng),而是異步地處理請(qǐng)求和響應(yīng)。
- 響應(yīng)式類型:負(fù)載均衡器的 API 使用了反應(yīng)式類型,如 Mono 和 Flux,它們是 Project Reactor 提供的反應(yīng)式類型。Mono 用于表示 0 或 1 個(gè)元素的異步序列,而 Flux 用于表示 0 到 N 個(gè)元素的異步序列。
- 背壓(Backpressure):反應(yīng)式編程支持背壓機(jī)制,即消費(fèi)者可以控制生產(chǎn)者生成數(shù)據(jù)的速度。這在處理大量并發(fā)請(qǐng)求時(shí)非常有用,可以避免因生產(chǎn)者過(guò)快生成數(shù)據(jù)而導(dǎo)致消費(fèi)者處理不過(guò)來(lái)。
- 錯(cuò)誤處理:反應(yīng)式編程提供了豐富的錯(cuò)誤處理機(jī)制,如 onErrorResume、retry 等操作符,可以在發(fā)生錯(cuò)誤時(shí)優(yōu)雅地處理異常情況。
- 組合和轉(zhuǎn)換:Mono 和 Flux 提供了豐富的操作符,用于組合和轉(zhuǎn)換異步數(shù)據(jù)流。這使得可以靈活地處理負(fù)載均衡請(qǐng)求和響應(yīng),滿足各種復(fù)雜的業(yè)務(wù)需求。
簡(jiǎn)單的示例:
import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; @RestController public class MyController { private final LoadBalancerClient loadBalancerClient; public MyController(LoadBalancerClient loadBalancerClient) { this.loadBalancerClient = loadBalancerClient; } @GetMapping("/call-service") public Mono<String> callService() { // 獲取服務(wù)實(shí)例 ServiceInstance serviceInstance = loadBalancerClient.choose("my-service").block(); // 使用 WebClient 發(fā)起反應(yīng)式請(qǐng)求 WebClient webClient = WebClient.builder() .baseUrl(serviceInstance.getUri().toString()) .build(); return webClient.get() .uri("/some-endpoint") .retrieve() .bodyToMono(String.class); } }
注意:上面的示例中使用了 block() 方法來(lái)同步獲取服務(wù)實(shí)例,這在實(shí)際應(yīng)用中可能不是最佳實(shí)踐。通常,應(yīng)該在整個(gè)調(diào)用鏈中保持反應(yīng)式編程的異步特性。但是,為了簡(jiǎn)化示例,這里使用了 block() 方法。在實(shí)際應(yīng)用中,應(yīng)該將服務(wù)實(shí)例的獲取和請(qǐng)求的發(fā)起都轉(zhuǎn)換為反應(yīng)式操作。
與 OpenFeign 集成
Spring Cloud 應(yīng)用程序中,spring-cloud-starter-loadbalancer 通常與 spring-cloud-starter-openfeign 或其他 HTTP 客戶端(如 WebClient)一起使用,以支持對(duì)服務(wù)發(fā)現(xiàn)的客戶端進(jìn)行負(fù)載均衡的調(diào)用。
當(dāng)使用 OpenFeign 聲明式 HTTP 客戶端時(shí),spring-cloud-starter-loadbalancer 會(huì)自動(dòng)集成以提供負(fù)載均衡功能。只需在 pom.xml 或 build.gradle 文件中包含相應(yīng)的依賴,并在 Feign 客戶端接口上使用 @FeignClient 注解指定服務(wù)名。
- Maven 依賴
<dependencies> <!-- ... 其他依賴 ... --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> <!-- ... 其他依賴 ... --> </dependencies>
- Feign 客戶端
@FeignClient(name = "my-service") public interface MyServiceClient { // 定義 HTTP 方法 @GetMapping("/some-endpoint") Mono<String> getSomething(); }
WebClient 集成
使用 WebClient 作為 HTTP 客戶端,可以通過(guò) spring-cloud-starter-loadbalancer 來(lái)實(shí)現(xiàn)服務(wù)間的負(fù)載均衡調(diào)用。需要?jiǎng)?chuàng)建一個(gè) WebClient.Builder bean,并使用 LoadBalancerExchangeFilterFunction 來(lái)自動(dòng)處理服務(wù)發(fā)現(xiàn)和負(fù)載均衡。
- 配置 WebClient Bean
@Bean public WebClient.Builder webClientBuilder(LoadBalancerClient loadBalancerClient) { return WebClient.builder() .baseUrl("lb://my-service") // 使用 'lb://' 前綴啟用負(fù)載均衡 .filter(new LoadBalancerExchangeFilterFunction(loadBalancerClient)); }
- 使用 WebClient 發(fā)起請(qǐng)求
@Autowired private WebClient.Builder webClientBuilder; public Mono<String> callService() { WebClient webClient = webClientBuilder.build(); return webClient.get() .uri("/some-endpoint") .retrieve() .bodyToMono(String.class); }
注意事項(xiàng):
- 確保 Spring Cloud 版本支持 spring-cloud-starter-loadbalancer。
- 從使用 Ribbon 遷移到 spring-cloud-starter-loadbalancer,請(qǐng)注意兩者之間的配置差異和 API 更改。
- 在使用 WebClient 時(shí),確保使用了正確的 URL 前綴(lb://)來(lái)啟用負(fù)載均衡。
- 在自定義負(fù)載均衡器時(shí),確保實(shí)現(xiàn)是線程安全的,并且能夠處理并發(fā)請(qǐng)求。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringSecurity實(shí)現(xiàn)自定義用戶認(rèn)證方案
Spring?Security?實(shí)現(xiàn)自定義用戶認(rèn)證方案可以根據(jù)具體需求和業(yè)務(wù)場(chǎng)景進(jìn)行設(shè)計(jì)和實(shí)施,滿足不同的安全需求和業(yè)務(wù)需求,這種靈活性使得認(rèn)證機(jī)制能夠更好地適應(yīng)各種復(fù)雜的環(huán)境和變化?,本文給大家介紹了SpringSecurity實(shí)現(xiàn)自定義用戶認(rèn)證方案,需要的朋友可以參考下2025-01-01Java的JSON轉(zhuǎn)換類庫(kù)GSON的基礎(chǔ)使用教程
GSON是谷歌開源的一款Java對(duì)象與JSON對(duì)象互相轉(zhuǎn)換的類庫(kù),Java的JSON轉(zhuǎn)換類庫(kù)GSON的基礎(chǔ)使用教程,需要的朋友可以參考下2016-06-06SpringBoot項(xiàng)目啟動(dòng)數(shù)據(jù)加載內(nèi)存的三種方法
一般來(lái)說(shuō),SpringBoot工程環(huán)境配置放在properties文件中,啟動(dòng)的時(shí)候?qū)⒐こ讨械膒roperties/yaml文件的配置項(xiàng)加載到內(nèi)存中,本文給大家介紹了SpringBoot項(xiàng)目啟動(dòng)數(shù)據(jù)加載內(nèi)存中的三種方法,需要的朋友可以參考下2024-04-04解決mybatisplus MetaObjectHandler 失效的問題
本文主要介紹了解決mybatisplus MetaObjectHandler 失效的問題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02