Ribbon 曾經是 Spring Cloud 家族默認的客戶端負載均衡工具,而 Spring Cloud LoadBalancer (SCLB) 是官方替換 Ribbon 的新實現。表面上它們都解決 “服務調用時選哪個實例” 的問題,但在理念、架構和生態上差異不小。
一、Ribbon? vs? SCLB
1. 定位和生態地位
Ribbon
Netflix OSS 出品,老一代的客戶端負載均衡器。
在 Spring Cloud Dalston ~ Greenwich 時代是默認選擇。
后來 Netflix OSS 宣布 進入維護模式(2018年起不再活躍發展)。
Spring Cloud LoadBalancer
Spring 團隊自研,替代 Ribbon。
完全獨立于 Netflix 生態,不再依賴過時組件。
與 Spring Boot 2.x/3.x、Reactor、WebClient、Feign 等深度集成。
2. 核心設計思路
Ribbon
侵入性較強:依賴
IClientConfig
、IRule
、IPing
等接口,配置體系復雜。強調“策略類 + 配置類”模式(比如 RoundRobinRule、ZoneAvoidanceRule)。
同步調用模型為主,雖然可擴展但偏“重量級”。
與
RestTemplate
深度耦合(通過@LoadBalanced RestTemplate
)。
Spring Cloud LoadBalancer
函數式 + 輕量化:核心是
ServiceInstanceListSupplier
(負責提供實例列表)和ReactorServiceInstanceLoadBalancer
(負責挑選實例)。完全 Reactor 化,支持響應式編程(Reactor/Flux/Mono),天然適配 WebClient。
API 更簡單,默認策略是 RoundRobin,但很容易定制。
更解耦,和 DiscoveryClient、Feign、gRPC 等可自由組合。
3. 擴展能力
Ribbon
有比較多的現成策略:
RoundRobinRule
、RandomRule
、RetryRule
、WeightedResponseTimeRule
…自定義需要繼承
IRule
,配置也要繞 Ribbon 的專用配置體系。支持 Zone 概念(跨機房/多可用區),適合 Netflix 內部環境,但在普通企業里很少用上。
Spring Cloud LoadBalancer
策略很“干凈”:只要實現
ReactorServiceInstanceLoadBalancer
接口即可。ServiceInstanceListSupplier 提供了天然的 hook:你可以在實例列表進入負載均衡前加上 過濾、排序、權重。
沒有 Ribbon 那種內置十幾個策略的復雜度,但用組合的方式,靈活度更高。
4. 與 Spring 生態的關系
Ribbon
被強綁定到
RestTemplate
+ Feign(老版本)。Spring Cloud Netflix 維護成本高,升級阻力大。
Spring Cloud LoadBalancer
未來路線核心組件,和 Spring Cloud Gateway、Feign 3.x、WebClient 全兼容。
官方推薦替代方案,Ribbon 已經標記 Deprecated。
隨 Spring Boot/Spring Cloud 版本更新,能持續獲得支持。
5. 性能與現代化
Ribbon
基于老舊同步模型(雖然功能全,但顯得笨重)。
沒有天然的 Reactor 支持,在響應式場景里不合拍。
Spring Cloud LoadBalancer
基于 Reactor,輕量、非阻塞,天然適合高并發場景。
使用
Flux<ServiceInstance>
,可以靈活疊加緩存、權重、健康檢查邏輯。更加云原生,能和 Kubernetes Service、Consul、Nacos 等平滑對接。
二、源碼說明
1.?核心抽象
Ribbon
結果:實例獲取、緩存、負載均衡策略,全都綁死在 Ribbon 的體系。
負載均衡器接口:
ILoadBalancer
內部維護實例列表(ServerList),并交給IRule
挑選。負載均衡策略接口:
IRule
public interface IRule {Server choose(Object key);void setLoadBalancer(ILoadBalancer lb);ILoadBalancer getLoadBalancer(); }
代表“從一堆服務實例里挑一個”。
Spring Cloud LoadBalancer (SCLB)
實例供應接口:
public interface ServiceInstanceListSupplier extends Supplier<Flux<List<ServiceInstance>>> {String getServiceId(); }
負責“提供候選實例列表”,來源可以是 DiscoveryClient、緩存、靜態配置。
策略接口:
public interface ReactorServiceInstanceLoadBalancer {Mono<Response<ServiceInstance>> choose(Request request); }
專注于“如何從候選列表里挑一個”。
結果:候選列表與選擇邏輯完全解耦,職責單一,而且基于 Reactor(非阻塞)。
2. Spring Cloud LoadBalancer 和 Feign 相對 Ribbon 的解耦性
看源碼上的調用鏈對比最明顯:
Ribbon + Feign
Feign 的LoadBalancerFeignClient
→ 直接調用RibbonLoadBalancerClient
→ 使用ILoadBalancer
+IRule
綁定。public class RibbonLoadBalancerClient implements LoadBalancerClient {@Overridepublic ServiceInstance choose(String serviceId) {ILoadBalancer loadBalancer = getLoadBalancer(serviceId);Server server = loadBalancer.chooseServer(null);return new RibbonServer(serviceId, server, isSecure(server), serverIntrospector(serviceId).getMetadata(server));} }
可以看到:Feign 和 Ribbon 耦合緊密,
ILoadBalancer
和IRule
必須都存在。SCLB + Feign(Spring Cloud 2020+)
Feign 的LoadBalancerFeignClient
→ 使用BlockingLoadBalancerClient
或ReactorLoadBalancerExchangeFilterFunction
。public class BlockingLoadBalancerClient implements LoadBalancerClient {private final LoadBalancerClientFactory clientFactory;@Overridepublic ServiceInstance choose(String serviceId) {ReactorServiceInstanceLoadBalancer loadBalancer = clientFactory.getInstance(serviceId, ReactorServiceInstanceLoadBalancer.class);// 核心是調用 loadBalancer.choose()} }
這里的關鍵:
Feign 只依賴于
ReactorServiceInstanceLoadBalancer
抽象,而不關心實例供應如何實現。ServiceInstanceListSupplier
可隨時替換(比如 Kubernetes、Consul、Nacos),Feign 本身無需改動。
👉 結論:Ribbon 時代 Feign 直接依賴 Ribbon 核心接口,導致強綁定;SCLB 下 Feign 只依賴于統一的 LoadBalancer 抽象,而實例來源和策略完全可插拔 → 解耦性更高。
三、Spring Cloud LoadBalancer 最佳實踐
1. 基礎使用
引入依賴
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
RestTemplate / WebClient 集成
@Bean
@LoadBalanced
public RestTemplate restTemplate(RestTemplateBuilder builder) {return builder.build();
}@Bean
@LoadBalanced
public WebClient.Builder webClientBuilder() {return WebClient.builder();
}
建議優先用 WebClient,因為它能發揮 SCLB 的 Reactor 非阻塞優勢。
2. 緩存與性能優化
SCLB 默認每次請求會調用 DiscoveryClient
獲取實例,可以用內置的 緩存供應器:
@Bean
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(ConfigurableApplicationContext context) {return ServiceInstanceListSupplier.builder().withDiscoveryClient().withCaching() // 啟用緩存.build(context);
}
這樣能減少注冊中心壓力,尤其是在高并發場景。
3. 自定義策略
簡單示例:基于元數據的優先級選擇
比如實例 metadata 里有 "zone": "shanghai"
,只要優先調用同城實例:
@Bean
ReactorServiceInstanceLoadBalancer zoneAwareLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> supplierProvider) {return new ReactorServiceInstanceLoadBalancer() {@Overridepublic Mono<Response<ServiceInstance>> choose(Request request) {return supplierProvider.getIfAvailable().get().next().map(instances -> {List<ServiceInstance> localZone = instances.stream().filter(i -> "shanghai".equals(i.getMetadata().get("zone"))).toList();if (!localZone.isEmpty()) {return new DefaultResponse(localZone.get(0));}return new DefaultResponse(instances.get(0));});}};
}
更復雜:權重路由
實現 ReactorServiceInstanceLoadBalancer
,結合 metadata.weight
字段,做加權隨機選擇。這相當于 Ribbon 的 WeightedResponseTimeRule
,但在 SCLB 里更靈活。
4. ServiceInstanceListSupplier 增強
SCLB 提供了“供應鏈”思想,常用擴展點:
過濾:過濾掉 metadata 標記為
"status=down"
的實例;排序:按響應時間/CPU負載排序,把健康的放前面;
包裝:組合多層供應器(比如先 DiscoveryClient → 再緩存 → 再 zone 過濾)。
這種鏈式增強比 Ribbon 的配置類清晰得多。
5. 與 Feign 配合
在新版 Spring Cloud 中,Feign 默認走 SCLB。最佳實踐:
配置
spring.cloud.loadbalancer.retry.enabled=true
→ 自動開啟重試機制;自定義
ReactorServiceInstanceLoadBalancer
,Feign 會自動走你的策略;如果想做更細粒度控制,可以寫
@FeignClient(configuration=...)
指定獨立的 LoadBalancer 配置。
6. 容錯與重試
SCLB 不再像 Ribbon 那樣內置 RetryRule,而是把重試交給 Spring Retry:
spring:cloud:loadbalancer:retry:enabled: trueretry-on-all-operations: truemax-retries-on-same-service-instance: 1max-retries-on-next-service-instance: 2
這樣能保證單實例失敗 → 自動切換下一個實例,避免單點問題。
7. 云原生環境最佳實踐
在 Kubernetes 上,推薦直接基于
spring-cloud-starter-kubernetes-client
+ SCLB,實例供應就是 Pod 列表;在 Nacos / Consul 場景下,直接使用對應 DiscoveryClient starter,SCLB 自動適配;
保持 ServiceInstance metadata 豐富(zone、weight、tag),方便做策略。
8. 遷移建議(Ribbon → SCLB)
RestTemplate 上的
@LoadBalanced
不需要動,底層自動切換為 SCLB;Feign 默認走 SCLB,不需要額外改動;
Ribbon 自定義的
IRule
策略,需要改寫成ReactorServiceInstanceLoadBalancer
;Ribbon 的 Zone/Weight 邏輯,遷移到
ServiceInstanceListSupplier
+ metadata 策略更清晰。
總結
最佳實踐關鍵就是 “解耦 + 插拔”:
實例來源 → DiscoveryClient + 緩存
實例增強 → Supplier 過濾/排序/權重
策略 → 自定義 LoadBalancer
調用 → WebClient / Feign
容錯 → Spring Retry