Spring?Cloud?Loadbalancer服務(wù)均衡負載器詳解
Spring Cloud Loadbalancer
1、簡介
Spring Cloud LoadBalancer 是 Spring Cloud 中提供客戶端負載均衡的組件之一,它的主要作用是在服務(wù)消費者和服務(wù)提供者之間實現(xiàn)負載均衡。
在微服務(wù)架構(gòu)中,服務(wù)提供者往往會有多個實例,這些實例可以部署在不同的節(jié)點或者不同的地理位置。而服務(wù)消費者需要從這些實例中選擇?個來處理請求,以避免單個實例過載或故障導致服務(wù)不可用。這時候就需要?個負載均衡組件來決定將請求分發(fā)到哪個實例上。Spring Cloud LoadBalancer 封裝了負載均衡算法,并提供了 LoadBalancerClient 接口,通過這個接口,應(yīng)用程序可以根據(jù)負載均衡策略從可用的服務(wù)實例列表中選擇?個實例來處理請求。
與傳統(tǒng)的負載均衡器相比,Spring Cloud LoadBalancer 的優(yōu)點在于它是?個基于應(yīng)用程序的負載均衡器,可以與 Spring Cloud 中的其他組件集成,如服務(wù)注冊中心、斷路器、配置中心等,從而實現(xiàn)更靈活、更高效的微服務(wù)架構(gòu)。
Spring Cloud 2020版本以后,默認移除了對Netflix的依賴,其中就包括Ribbon,官?默認推薦使用Spring Cloud Loadbalancer正式替換Ribbon,并成為了Spring Cloud負載均衡器的唯?實現(xiàn)。
2、實現(xiàn)原理
第1次訪問:

節(jié)點數(shù)量狀態(tài)變化主動推送消費者實例更新本地節(jié)點數(shù)據(jù)

3、模擬實現(xiàn)
在本節(jié)中,我們使用article-service和video-service來模擬服務(wù)間的負載均衡。
服務(wù)提供者:
這里我們使用video-service作為服務(wù)提供者,直接開啟三個video-service模擬服務(wù)集群來提供服務(wù)

按照以上步驟,我們直接在本地的8001、8002、8003端口上配置了三個服務(wù)提供者video-service,然后逐一啟動。

服務(wù)消費者:
在消費者端引入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
<version>3.1.3</version>
</dependency>Java Config實例化RestTemplate對象,并使用@LoadBalanced聲明負載均衡當使用負載均衡器來調(diào)用多個服務(wù)實例時,可以使用 @Balanced 注解標記 RestTemplate 或WebClient 實例。這會自動啟用負載均衡功能,從而使請求在多個服務(wù)實例之間進行分布。
在使用@Balanced 注解時,需要確保在應(yīng)用程序中已配置了負載均衡器(如 Ribbon 或 Spring CloudLoadBalancer)。同時,需要確保 RestTemplate 或 WebClient 已經(jīng)配置為使用負載均衡器。
這里就不書寫配置類,直接在啟動類中向IoC容器注入RestTemplate對象
@SpringBootApplication
@EnableFeignClients //開啟OpenFeign實現(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);
}
}在使用時注入restTemplate對象,利用RestTemplate對象發(fā)起HTTP請求,注意:請求IP地址的地方此時改為要遠程訪問的服務(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、使用細節(jié)
Spring Cloud提供了自己的客戶端負載均衡器抽象和實現(xiàn)。為了實現(xiàn)負載均衡機制,新增了ReactiveLoadBalancer接口,并提供了基于輪詢和隨機的實現(xiàn)。
為了從反應(yīng)式的ServiceInstanceListSupplier中獲取實例進行選擇,我們使用了?個ServiceInstanceListSupplier的基于服務(wù)發(fā)現(xiàn)的實現(xiàn),該實現(xiàn)使用了類路徑下的Discovery Client來檢索可用實例。
5、切換負載均衡算法
默認情況下使用的ReactiveLoadBalancer實現(xiàn)是RoundRobinLoadBalancer。要切換到不同的實現(xiàn),無論是選擇性的服務(wù)還是全部服務(wù),您都可以使用自定義的LoadBalancer配置機制。
例如,可以通過@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進?注釋,或者在組件掃描范圍之外。
應(yīng)用代碼:
@SpringBootApplication
@LoadBalancerClients({
@LoadBalancerClient(value = "video-service",
configuration = CustomLoadBalancerConfiguration.class)
})
@EnableFeignClients //開啟OpenFeign實現(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)用,并自動進行負載均衡選擇實例。
6、緩存方案
除了基本的 ServiceInstanceListSupplier 實現(xiàn)每次需要選擇實例時都通過 DiscoveryClient 檢索實例之外,我們提供了兩種緩存實現(xiàn),以提高效率:
- Caffeine-backed LoadBalancer緩存實現(xiàn)
- 默認 LoadBalancer 緩存實現(xiàn)
如果在類路徑中沒有 Caffeine,則會使用 DefaultLoadBalancerCache。它自動隨著 spring-cloud-starter-loadbalancer 提供。
如果要使用 Caffeine 而不是默認緩存,請將 com.github.ben-manes.caffeine:caffeine 依賴項添加到類路徑中。
LoadBalancer 緩存配置
您可以通過將符合 Spring Boot 字符串到 Duration 轉(zhuǎn)換器語法的字符串作為spring.cloud.loadbalancer.cache.ttl 屬性的值,設(shè)置自己的 ttl 值(寫入后過多長時間條目應(yīng)過期),以 Duration 表示。您還可以通過設(shè)置 spring.cloud.loadbalancer.cache.capacity 屬性的值,設(shè)置自己的 LoadBalancer 緩存初始容量。
默認設(shè)置包括將 ttl 設(shè)置為 35 秒,而默認的 initialCapacity 為 256。
在 Spring Cloud LoadBalancer 中,為了減少對服務(wù)注冊中心的頻繁調(diào)用,提?服務(wù)調(diào)用的性能,LoadBalancer 會緩存服務(wù)實例列表。當?個請求需要訪問某個服務(wù)時,LoadBalancer 會先從緩存中查找可用的服務(wù)實例列表,如果緩存中沒有可用的實例列表,則會重新從服務(wù)注冊中心獲取服務(wù)實例列表。因此,調(diào)整 spring.cloud.loadbalancer.cache.capacity 的值可以影響 LoadBalancer 緩存的大小,從而影響緩存命中率和性能。
上面的配置將負載均衡器的緩存容量限制為 100 個實例。當緩存容量達到上限時,新的實例將覆蓋舊的實例。這樣,緩存將始終包含最新的實例列表,并且不會占用過多的內(nèi)存資源。
我們還可以通過將 spring.cloud.loadbalancer.cache.enabled 的值設(shè)置為 false,完全禁用LoadBalancer 緩存。
雖然基本的非緩存實現(xiàn)對于原型設(shè)計和測試很有用,但比緩存版本要低效得多,因此我們建議在生產(chǎn)中始終使用緩存版本。如果發(fā)現(xiàn)已經(jīng)由 DiscoveryClient 實現(xiàn)(例如 EurekaDiscoveryClient)進行了緩存,則應(yīng)禁用負載平衡器緩存以防止雙重緩存。
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)
我們要實現(xiàn)這些方法來指定負載均衡前后應(yīng)該發(fā)?的操作。
onStart(Request<RC> request)
以 Request 對象作為參數(shù)。它包含用于選擇適當實例的數(shù)據(jù),包括下游客戶端請求和提示。
onStartRequest 也以 Request 對象作為參數(shù),此外還有 Response<T> 對象。
另一方面,完成時提供了 CompletionContext 對象給
onComplete(CompletionContext<RES, T, RC>completionContext)
方法。它包含 LoadBalancer 響應(yīng),包括所選服務(wù)實例、針對該服務(wù)實例執(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) {
// 在負載均衡之后執(zhí)?的操作
log.info("Load balancing completed for request: " + completionContext.getLoadBalancerRequest() +
", with status: " + completionContext.status());
log.info("《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《");
}
}執(zhí)行http://localhost:8101/remote-call,觀察輸出日志.
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
解決@ConfigurationProperties注解的使用及亂碼問題
這篇文章主要介紹了解決@ConfigurationProperties注解的使用及亂碼問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10
SpringBoot Java后端實現(xiàn)okhttp3超時設(shè)置的方法實例
Okhttp的使用沒有httpClient廣泛,網(wǎng)上關(guān)于Okhttp設(shè)置代理的方法很少,下面這篇文章主要給大家介紹了關(guān)于SpringBoot Java后端實現(xiàn)okhttp3超時設(shè)置的相關(guān)資料,需要的朋友可以參考下2021-10-10
使用JPA雙向多對多關(guān)聯(lián)關(guān)系@ManyToMany
這篇文章主要介紹了使用JPA雙向多對多關(guān)聯(lián)關(guān)系@ManyToMany,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06
Spring Task定時任務(wù)每天零點執(zhí)行一次的操作
這篇文章主要介紹了Spring Task定時任務(wù)每天零點執(zhí)行一次的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09

