Spring?Cloud?Loadbalancer服務(wù)均衡負(fù)載器詳解
Spring Cloud Loadbalancer
1、簡介
Spring Cloud LoadBalancer 是 Spring Cloud 中提供客戶端負(fù)載均衡的組件之一,它的主要作用是在服務(wù)消費(fèi)者和服務(wù)提供者之間實(shí)現(xiàn)負(fù)載均衡。
在微服務(wù)架構(gòu)中,服務(wù)提供者往往會(huì)有多個(gè)實(shí)例,這些實(shí)例可以部署在不同的節(jié)點(diǎn)或者不同的地理位置。而服務(wù)消費(fèi)者需要從這些實(shí)例中選擇?個(gè)來處理請求,以避免單個(gè)實(shí)例過載或故障導(dǎo)致服務(wù)不可用。這時(shí)候就需要?個(gè)負(fù)載均衡組件來決定將請求分發(fā)到哪個(gè)實(shí)例上。Spring Cloud LoadBalancer 封裝了負(fù)載均衡算法,并提供了 LoadBalancerClient 接口,通過這個(gè)接口,應(yīng)用程序可以根據(jù)負(fù)載均衡策略從可用的服務(wù)實(shí)例列表中選擇?個(gè)實(shí)例來處理請求。
與傳統(tǒng)的負(fù)載均衡器相比,Spring Cloud LoadBalancer 的優(yōu)點(diǎn)在于它是?個(gè)基于應(yīng)用程序的負(fù)載均衡器,可以與 Spring Cloud 中的其他組件集成,如服務(wù)注冊中心、斷路器、配置中心等,從而實(shí)現(xiàn)更靈活、更高效的微服務(wù)架構(gòu)。
Spring Cloud 2020版本以后,默認(rèn)移除了對Netflix的依賴,其中就包括Ribbon,官?默認(rèn)推薦使用Spring Cloud Loadbalancer正式替換Ribbon,并成為了Spring Cloud負(fù)載均衡器的唯?實(shí)現(xiàn)。
2、實(shí)現(xiàn)原理
第1次訪問:
節(jié)點(diǎn)數(shù)量狀態(tài)變化主動(dòng)推送消費(fèi)者實(shí)例更新本地節(jié)點(diǎn)數(shù)據(jù)
3、模擬實(shí)現(xiàn)
在本節(jié)中,我們使用article-service和video-service來模擬服務(wù)間的負(fù)載均衡。
服務(wù)提供者:
這里我們使用video-service作為服務(wù)提供者,直接開啟三個(gè)video-service模擬服務(wù)集群來提供服務(wù)
按照以上步驟,我們直接在本地的8001、8002、8003端口上配置了三個(gè)服務(wù)提供者video-service,然后逐一啟動(dòng)。
服務(wù)消費(fèi)者:
在消費(fèi)者端引入依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-loadbalancer</artifactId> <version>3.1.3</version> </dependency>
Java Config實(shí)例化RestTemplate對象,并使用@LoadBalanced聲明負(fù)載均衡當(dāng)使用負(fù)載均衡器來調(diào)用多個(gè)服務(wù)實(shí)例時(shí),可以使用 @Balanced 注解標(biāo)記 RestTemplate 或WebClient 實(shí)例。這會(huì)自動(dòng)啟用負(fù)載均衡功能,從而使請求在多個(gè)服務(wù)實(shí)例之間進(jìn)行分布。
在使用@Balanced 注解時(shí),需要確保在應(yīng)用程序中已配置了負(fù)載均衡器(如 Ribbon 或 Spring CloudLoadBalancer)。同時(shí),需要確保 RestTemplate 或 WebClient 已經(jīng)配置為使用負(fù)載均衡器。
這里就不書寫配置類,直接在啟動(dòng)類中向IoC容器注入RestTemplate對象
@SpringBootApplication @EnableFeignClients //開啟OpenFeign實(shí)現(xiàn)服務(wù)間REST通信 public class ArticleServiceApplication { @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(ArticleServiceApplication.class, args); } }
在使用時(shí)注入restTemplate對象,利用RestTemplate對象發(fā)起HTTP請求,注意:請求IP地址的地方此時(shí)改為要遠(yuǎn)程訪問的服務(wù)名,如:video-service。
@RestController public class ArticleController { @Resource private ArticleService articleService; @GetMapping("/list") public List<Article> list(){ return articleService.list(); } @Resource private RestTemplate restTemplate; @GetMapping("/remote-call") public String remoteCall(){ String result = restTemplate.getForObject("http://video-service/video?articleId=1648", String.class); return "remote:" + result; } }
4、使用細(xì)節(jié)
Spring Cloud提供了自己的客戶端負(fù)載均衡器抽象和實(shí)現(xiàn)。為了實(shí)現(xiàn)負(fù)載均衡機(jī)制,新增了ReactiveLoadBalancer接口,并提供了基于輪詢和隨機(jī)的實(shí)現(xiàn)。
為了從反應(yīng)式的ServiceInstanceListSupplier中獲取實(shí)例進(jìn)行選擇,我們使用了?個(gè)ServiceInstanceListSupplier的基于服務(wù)發(fā)現(xiàn)的實(shí)現(xiàn),該實(shí)現(xiàn)使用了類路徑下的Discovery Client來檢索可用實(shí)例。
5、切換負(fù)載均衡算法
默認(rèn)情況下使用的ReactiveLoadBalancer實(shí)現(xiàn)是RoundRobinLoadBalancer。要切換到不同的實(shí)現(xiàn),無論是選擇性的服務(wù)還是全部服務(wù),您都可以使用自定義的LoadBalancer配置機(jī)制。
例如,可以通過@LoadBalancerClient注釋傳遞以下配置,以切換到使用RandomLoadBalancer:
package com.dw.config; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer; import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer; import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory; import org.springframework.context.annotation.Bean; import org.springframework.core.env.Environment; public class CustomLoadBalancerConfiguration { @Bean ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) { String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); return new RandomLoadBalancer(loadBalancerClientFactory .getLazyProvider(name, ServiceInstanceListSupplier.class), name); } }
注意:您作為 @ LoadBalancerClient或 @ LoadBalancerClients配置參數(shù)傳遞的類不應(yīng)使用@configuration進(jìn)?注釋,或者在組件掃描范圍之外。
應(yīng)用代碼:
@SpringBootApplication @LoadBalancerClients({ @LoadBalancerClient(value = "video-service", configuration = CustomLoadBalancerConfiguration.class) }) @EnableFeignClients //開啟OpenFeign實(shí)現(xiàn)服務(wù)間REST通信 public class ArticleServiceApplication { @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(ArticleServiceApplication.class, args); } }
應(yīng)用程序可以使用 Spring Cloud 提供的 LoadBalancerClient 對象來發(fā)起對 "video-service" 服務(wù)的調(diào)用,并自動(dòng)進(jìn)行負(fù)載均衡選擇實(shí)例。
6、緩存方案
除了基本的 ServiceInstanceListSupplier 實(shí)現(xiàn)每次需要選擇實(shí)例時(shí)都通過 DiscoveryClient 檢索實(shí)例之外,我們提供了兩種緩存實(shí)現(xiàn),以提高效率:
- Caffeine-backed LoadBalancer緩存實(shí)現(xiàn)
- 默認(rèn) LoadBalancer 緩存實(shí)現(xiàn)
如果在類路徑中沒有 Caffeine,則會(huì)使用 DefaultLoadBalancerCache。它自動(dòng)隨著 spring-cloud-starter-loadbalancer 提供。
如果要使用 Caffeine 而不是默認(rèn)緩存,請將 com.github.ben-manes.caffeine:caffeine 依賴項(xiàng)添加到類路徑中。
LoadBalancer 緩存配置
您可以通過將符合 Spring Boot 字符串到 Duration 轉(zhuǎn)換器語法的字符串作為spring.cloud.loadbalancer.cache.ttl 屬性的值,設(shè)置自己的 ttl 值(寫入后過多長時(shí)間條目應(yīng)過期),以 Duration 表示。您還可以通過設(shè)置 spring.cloud.loadbalancer.cache.capacity 屬性的值,設(shè)置自己的 LoadBalancer 緩存初始容量。
默認(rèn)設(shè)置包括將 ttl 設(shè)置為 35 秒,而默認(rèn)的 initialCapacity 為 256。
在 Spring Cloud LoadBalancer 中,為了減少對服務(wù)注冊中心的頻繁調(diào)用,提?服務(wù)調(diào)用的性能,LoadBalancer 會(huì)緩存服務(wù)實(shí)例列表。當(dāng)?個(gè)請求需要訪問某個(gè)服務(wù)時(shí),LoadBalancer 會(huì)先從緩存中查找可用的服務(wù)實(shí)例列表,如果緩存中沒有可用的實(shí)例列表,則會(huì)重新從服務(wù)注冊中心獲取服務(wù)實(shí)例列表。因此,調(diào)整 spring.cloud.loadbalancer.cache.capacity 的值可以影響 LoadBalancer 緩存的大小,從而影響緩存命中率和性能。
上面的配置將負(fù)載均衡器的緩存容量限制為 100 個(gè)實(shí)例。當(dāng)緩存容量達(dá)到上限時(shí),新的實(shí)例將覆蓋舊的實(shí)例。這樣,緩存將始終包含最新的實(shí)例列表,并且不會(huì)占用過多的內(nèi)存資源。
我們還可以通過將 spring.cloud.loadbalancer.cache.enabled 的值設(shè)置為 false,完全禁用LoadBalancer 緩存。
雖然基本的非緩存實(shí)現(xiàn)對于原型設(shè)計(jì)和測試很有用,但比緩存版本要低效得多,因此我們建議在生產(chǎn)中始終使用緩存版本。如果發(fā)現(xiàn)已經(jīng)由 DiscoveryClient 實(shí)現(xiàn)(例如 EurekaDiscoveryClient)進(jìn)行了緩存,則應(yīng)禁用負(fù)載平衡器緩存以防止雙重緩存。
spring.cloud.loadbalancer.cache.enabled=true spring.cloud.loadbalancer.cache.ttl=120s spring.cloud.loadbalancer.cache.capacity=100
7、 生命周期
使用自定義 LoadBalancer 配置注冊的?種有?的 bean 類型是 LoadBalancerLifecycle。
LoadBalancerLifecycle bean 提供了回調(diào)?法,命名如下:
onStart(Request<RC> request) onStartRequest(Request<RC> request, Response<T> lbResponse) onComplete(CompletionContext<RES, T, RC> completionContext)
我們要實(shí)現(xiàn)這些方法來指定負(fù)載均衡前后應(yīng)該發(fā)?的操作。
onStart(Request<RC> request)
以 Request 對象作為參數(shù)。它包含用于選擇適當(dāng)實(shí)例的數(shù)據(jù),包括下游客戶端請求和提示。
onStartRequest 也以 Request 對象作為參數(shù),此外還有 Response<T>
對象。
另一方面,完成時(shí)提供了 CompletionContext 對象給
onComplete(CompletionContext<RES, T, RC>completionContext)
方法。它包含 LoadBalancer 響應(yīng),包括所選服務(wù)實(shí)例、針對該服務(wù)實(shí)例執(zhí)行的請求的狀態(tài),(如果有)返回給下游客戶端的響應(yīng),以及(如果發(fā)生異常)相應(yīng)的 Throwable。
supports(Class requestContextClass, Class responseClass, Class serverTypeClass)
方法可用于確定所討論的處理器是否處理提供的類型的對象。如果未被?戶覆蓋,則它返回 true。
案例:
@Component @Slf4j public class CustomLoadBalancerLifecycle implements LoadBalancerLifecycle { @Override public void onStart(Request request) { log.info("》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》"); log.info("Starting load balancing for request: " + request); } @Override public void onStartRequest(Request request, Response lbResponse) { log.info("Selected service instance: " + lbResponse.getServer()); } @Override public void onComplete(CompletionContext completionContext) { // 在負(fù)載均衡之后執(zhí)?的操作 log.info("Load balancing completed for request: " + completionContext.getLoadBalancerRequest() + ", with status: " + completionContext.status()); log.info("《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《"); } }
執(zhí)行http://localhost:8101/remote-call,觀察輸出日志.
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
解決@ConfigurationProperties注解的使用及亂碼問題
這篇文章主要介紹了解決@ConfigurationProperties注解的使用及亂碼問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10SpringBoot Java后端實(shí)現(xiàn)okhttp3超時(shí)設(shè)置的方法實(shí)例
Okhttp的使用沒有httpClient廣泛,網(wǎng)上關(guān)于Okhttp設(shè)置代理的方法很少,下面這篇文章主要給大家介紹了關(guān)于SpringBoot Java后端實(shí)現(xiàn)okhttp3超時(shí)設(shè)置的相關(guān)資料,需要的朋友可以參考下2021-10-10使用JPA雙向多對多關(guān)聯(lián)關(guān)系@ManyToMany
這篇文章主要介紹了使用JPA雙向多對多關(guān)聯(lián)關(guān)系@ManyToMany,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06Spring Task定時(shí)任務(wù)每天零點(diǎn)執(zhí)行一次的操作
這篇文章主要介紹了Spring Task定時(shí)任務(wù)每天零點(diǎn)執(zhí)行一次的操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09