[高可用/負載均衡] Ribbon LoadBalancer: 開源的客戶端式負載均衡框架
0 序言
- 某項目上,原先為自建的數據庫集群提供了負載均衡IP服務器(簡稱: ELB IP Server),客戶端的數據庫請求URL都統一走ELB IP。但隨著業務量的增長,識別到一個嚴峻的現實:
- 其一,考慮到未來的業務增長情況,云廠商提供的 ELB IP Server 云服務的入網帶寬必將完全無法滿足本項目的訴求。
- 其二,云廠商提供的 ELB IP Server 的費用較為昂貴,實在是不劃算。
除了入網帶寬的使用量較高外,云廠商ELB 服務提供的其他方面的資源指標,使用量均極低(有浪費錢的嫌疑)。
- 為此開始嘗試:取消服務端式負載均衡器,自行實現客戶端式的負載均衡器。
經過一番研究,開源的、支持Java、與
spring生態框架獨立/解耦的、負載均衡器Ribbon,成為個人的首選。即:筆者此時的訴求之一是,不需要引入
spring框架,與其解耦。
1 概述:Ribbon LoadBalancer: 開源負載均衡器
負載均衡的概念
- 負載均衡是一種通過【分發請求】來優化服務器資源利用率和提高系統性能的技術。
它在微服務架構中尤為重要,常見的負載均衡方式包括服務端負載均衡和客戶端負載均衡。

- 服務端負載均衡是指請求首先被發送到【負載均衡服務器】,然后由該服務器根據【負載均衡算法】(如輪詢、最小連接數等)將【請求分發】到后端服務器進行處理。
- 常見的服務端負載均衡工具包括: 硬件設備(如F5)和軟件(如Nginx、LVS)。
- 這種方式的優點是: 客戶端無感知、無需關心負載均衡的邏輯,所有的均衡操作都由服務端完成。

- 客戶端負載均衡則是由客戶端直接從服務注冊中心(如Nacos、Eureka)獲取服務列表,并根據負載均衡算法選擇目標服務器進行請求分發。
以
Spring Cloud中的Ribbon為例,客戶端通過RestTemplate觸發負載均衡。
客戶端負載均衡的特點是無需額外的負載均衡服務器(例如: ELB IP Server),分發邏輯完全由客戶端實現。

- 兩者的主要區別在于:負載均衡的實現位置。
服務端負載均衡依賴于專門的負載均衡服務器,而客戶端負載均衡則由客戶端自行完成分發邏輯。
客戶端式負載均衡方案的實現原理
- ?服務發現客戶端?,從注冊中心獲取服務實例列表并緩存。
- 客戶端請求被 ?負載均衡攔截器? 截獲(如 @LoadBalanced 標記的 RestTemplate/WebClient)。
org.springframework.cloud.client.loadbalancer.LoadBalanced
org.springframework.web.client.RestTemplate
- 攔截器調用 ?
LoadBalancerClient。
org.springframework.cloud.client.loadbalancer.LoadBalancerClient
org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient
4.? LoadBalancerClient? 調用底層的負載均衡器 (Ribbon / SCL) 選擇一個實例。
5. 負載均衡器根據 ?負載均衡策略? 從可用實例列表中選擇一個目標實例。
6. 請求最終被?轉發到選定的實例。
關鍵問題:負載均衡與請求客戶端、連接池的集成
Ribbon等本身只是一個客戶端負載均衡器,它負責從服務列表里挑一臺機器,把原請求 URL 中的“服務名”替換成這臺服務器的真實 IP+端口。
真正發出 HTTP 請求的是下游的 HTTP 客戶端;
- 若還想把“連接池”能力加進來,就是把這個客戶端換成支持池化的實現(
OkHttp/Apache HttpClient),并讓它復用 Ribbon 等負載均衡框架已挑好的地址。
Ribbon LoadBalancer: 開源的客戶端式負載均衡框架
- Ribbon
- Ribbon有很多子模塊,官方文檔中說明,目前 Netflix 公司主要用于生產環境的 Ribbon 子模塊如下:
ribbon-core:Ribbon 的核心API。ribbon-loadbalancer:可以獨立使用或與其他模塊一起使用的負載均衡器 API。ribbon-eureka:Ribbon 結合 注冊中心 Eureka 客戶端的 API,為負載均衡器提供動態服務注冊列表信息。

Ribbon LoadBalancer
- 起源于 ?Netflix OSS,曾是 Spring Cloud ?默認的客戶端負載均衡解決方案。
- Ribbon 是一個獨立的、較為成熟的庫,被廣泛集成到 Spring Cloud Netflix 組件(如 Zuul、Feign)中。
- 已進入維護模式,Netflix 官方不再積極開發新功能。
- 技術架構與依賴?
- ?非響應式 (阻塞式):?? 核心 API 基于線程池和阻塞調用,在響應式編程場景下兼容性較差。
- ?依賴較重:?? 包含大量 Netflix 的內部組件 (如 Archaius 配置系統),包體積和復雜度較高。
- ?獨立的負載均衡器:?? 需要額外的客戶端負載均衡器實現 (如 RibbonLoadBalancerClient)。
springcloud 與 ribbon 整合
此小節旨在解釋 spring cloud 項目中,如何與 ribbon 集成。ribbon 也可完全獨立于 spring 項目,獨立運行。
Ribbon 與 RestTemplate 整合使用
- 在
Spring Cloud構建的微服務系統中,Ribbon作為服務消費者的負載均衡器,有2種使用方式:
- 一種是和
RestTemplate相結合;- 另一種是和
Feign相結合。
- 那么,Spring Cloud框架中,Ribbon (負載均衡器) 是如何與 Spring 的 RestTemplate / WebClient 集成的?
下面用一張圖來看看 RestTemplate 基于 Ribbon 的遠程調用:

RestTemplate本身是不具備【負載均衡】的能力的。
1 RestTemplate 是 Spring Resources 中一個訪問第三方 RESTful API 接口的網絡請求框架,用于執行HTTP請求。
2 其暴露了一系列的模板方法API,便于操作底層的HTTP客戶端庫,如JDK的HttpURLConnection、Apache HttpComponents等。
3 RestTemplate 是用來消費 REST 服務的,所以 RestTemplate 的主要方法都與 REST 的 Http協議的一些方法緊密相連,例如 HEAD、GET、POST、PUT、DELETE 和 OPTIONS 等方法。
這些方法在 RestTemplate 類對應的方法為 headForHeaders()、getForObject()、postForObject()、put() 和 delete() 等。
4 RestTemplate通常作為【共享組件】使用,其配置不支持【并發修改】,因此通常在【啟動時】準備好配置。
如果需要,可以在啟動時創建多個配置不同的RestTemplate實例。
這些實例可以使用相同的底層`ClientHttpRequestFactory`,如果它們需要共享HTTP客戶端資源。
- 如果
RestTemplate未使用@LoadBalanced標記,就通過服務名的形式來調用,必然會報錯。- 用
@LoadBalanced標記后,調用RestTemplate的REST方法就會通過【負載均衡】的方式通過一定的負載策略【路由】到某個【服務實例】上。此時,其底層負責負載均衡的組件就是
Ribbon。
springcloud 、注冊中心 eureka 、負載均衡器 ribbon 三者的整合
- 與 eureka 整合到 springcloud 類似,springcloud 提供了對應的
spring-cloud-starter-netflix-eureka-client(server)依賴包 ribbon則整合到了spring-cloud-starter-netflix-ribbon中。
一般也不需要單獨引入 ribbon 的依賴包,
spring-cloud-starter-netflix-eureka-client中已經依賴了spring-cloud-starter-netflix-ribbon。
因此,我們引入了spring-cloud-starter-netflix-eureka-client就可以使用 Ribbon 的功能了。

springcloud 、注冊中心 nacos 、負載均衡器 ribbon 三者的整合
略,類同 eureka 。
客戶端式負載均衡框架的同類競品項目
- ?Spring Cloud LoadBalancer (SCL)
- Spring 官方在 ?Spring Cloud Hoxton (2020年)?? 推出,旨在替代 Ribbon。
- 是 ?Spring Cloud Commons? 項目的一部分,與 Spring 生態集成度更高。
- 目前作為 ?Spring Cloud 官方推薦的負載均衡解決方案,持續更新迭代。
spring項目中,若同時引了
spring-cloud-starter-netflix-ribbon與spring-cloud-loadbalancer會沖突,用spring.cloud.loadbalancer.ribbon.enabled=false可回退到Ribbon。
- 技術架構與依賴?
- ?響應式優先:?? 核心接口 ReactiveLoadBalancer 基于 ?Project Reactor?(Reactor Core),天然支持響應式編程,同時對阻塞式調用提供適配。
- ?輕量級:?? 源碼簡潔,依賴少 (spring-cloud-starter-loadbalancer),啟動更快。
- ?Spring原生集成:?? 與 Spring 框架深度集成(如 Environment、BeanFactory),配置管理更簡單。(既是優點,也是缺點)
Maven依賴
<!-- 客戶端式負載均衡器 https://github.com/Netflix/ribbon | https://mvnrepository.com/artifact/com.netflix.ribbon/ribbon -->
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon</artifactId>
<!-- 2.7.18 -->
<version>${ribbon.version}</version>
</dependency>
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon-core</artifactId>
<version>${ribbon.version}</version>
</dependency>
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon-loadbalancer</artifactId>
<version>${ribbon.version}</version>
</dependency>
2 Ribbon LoadBalancer 核心 API
- IClientConfig:Ribbon 客戶端配置類,默認實現是 DefaultClientConfigImpl。
- IRule:負載均衡策略規則組件,默認實現是 ZoneAvoidanceRule。
- IPing:判斷 Server 是否存活,默認實現是 DummyPing,永遠都是返回 true。
- ServerList:獲取 Server 的組件,默認實現類為 ConfigurationBasedServerList,從配置文件獲取。
- ServerListUpdater:Server 列表更新組件,默認實現類為 PollingServerListUpdater。
- ServerListFilter:過濾可用的 Server 列表,默認實現類為 ZonePreferenceServerListFilter。
- RibbonLoadBalancerContext:負載均衡客戶端。
- RetryHandler:重試處理器,默認實現類為 DefaultLoadBalancerRetryHandler。
IClientConfig : 客戶端配置
com.netflix.client.config.IClientConfig: 管理客戶端配置的核心接口,它的默認實現類是DefaultClientConfigImpl。
可以看到在創建
IClientConfig時,設置了 Ribbon 客戶端默認的連接和讀取超時時間為 1 秒,例如讀取如果超過1秒,就會返回超時,這兩個一般需要根據實際情況來調整。
import com.netflix.client.config.IClientConfig;
import com.netflix.client.config.CommonClientConfigKey;
@Bean
@ConditionalOnMissingBean
public IClientConfig ribbonClientConfig() {
DefaultClientConfigImpl config = new DefaultClientConfigImpl();
// 加載配置
config.loadProperties(this.name);
// 連接超時默認 1 秒
config.set(CommonClientConfigKey.ConnectTimeout, DEFAULT_CONNECT_TIMEOUT);
// 讀取超時默認 1 秒
config.set(CommonClientConfigKey.ReadTimeout, DEFAULT_READ_TIMEOUT);
config.set(CommonClientConfigKey.GZipPayload, DEFAULT_GZIP_PAYLOAD);
return config;
}
com.netflix.client.config.CommonClientConfigKey
這個類定義了 Ribbon 客戶端相關的所有配置的鍵常量,可以通過這個類來看有哪些配置。
- 進入到
DefaultClientConfigImpl,可以看到 CommonClientConfigKey 中的每個配置都對應了一個默認值。
在加載配置的時候,如果用戶沒有定制配置,就會使用默認的配置。
https://github.com/Netflix/ribbon/blob/v2.7.18/ribbon-archaius/src/main/java/com/netflix/client/config/DefaultClientConfigImpl.java
https://github.com/Netflix/ribbon/blob/v2.7.18/ribbon-core/src/test/java/com/netflix/client/config/DefaultClientConfigImplTest.java
也可以在配置文件中定制配置,例如配置超時和重試:
# 全局配置
ribbon:
# 客戶端讀取超時時間
ReadTimeout: 3000
# 客戶端連接超時時間
ConnectTimeout: 3000
# 默認只重試 GET,設置為 true 時將重試所有類型,如 POST、PUT、DELETE
OkToRetryOnAllOperations: false
# 重試次數
MaxAutoRetries: 1
# 最多重試幾個實例
MaxAutoRetriesNextServer: 1
# 只針對 demo-producer 客戶端
demo-producer:
ribbon:
# 客戶端讀取超時時間
ReadTimeout: 5000
# 客戶端連接超時時間
ConnectTimeout: 3000
IRule : 均衡策略
IRule是最終選擇 Server 的策略規則類,核心的接口就是choose。
public interface IRule{
// 選擇 Server
public Server choose(Object key);
// 設置 ILoadBalancer
public void setLoadBalancer(ILoadBalancer lb);
// 獲取 ILoadBalancer
public ILoadBalancer getLoadBalancer();
}
Ribbon提供了豐富的負載均衡策略,我們也可以通過配置指定使用某個均衡策略。下面是整個Ribbon提供的 IRule 均衡策略。

| 策略類 | 命名 | 描述 |
|---|---|---|
| RandomRule | 隨機策略 | 隨機選擇 server |
| RoundRobinRule | 輪詢策略 | 按順序循環選擇 server |
| RetryRule | 重試策略 | 在一個配置時間段內當選擇 server 不成功,則一直嘗試選擇一個可用的 server |
| BestAvailableRule | 最低并發策略 | 逐個考察 server,如果 server 斷路器打開,則忽略,再選擇其中并發連接最低的 server |
| AvailabilityFilteringRule | 可用過濾策略 | 過濾掉一直連接失敗并被標記為 circuit tripped 的 server,過濾掉那些高并發連接的 server(active connections 超過配置的閾值) |
| ResponseTimeWeightedRule | 響應時間加權策略 | 根據 server 的響應時間分配權重。響應時間越長,權重越低,被選擇到的概率就越低;響應時間越短,權重越高,被選擇到的概率就越高。這個策略很貼切,綜合了各種因素,如:網絡、磁盤、IO 等,這些因素直接影響著響應時間 |
| ZoneAvoidanceRule | 區域權衡策略 | 綜合判斷 server 所在區域的性能和 server 的可用性輪詢選擇 server,并且判定一個 AWS Zone 的運行性能是否可用,剔除不可用的 Zone 中的所有 server |
例如:
RandomRule=>com.netflix.loadbalancer.RandomRule
- RoundRobinRule:輪詢
- RandomRule:隨機
- RetryRule:先按照輪詢策略獲取服務,如果獲取服務失敗則在指定時間內進行重試,獲取可用的服務
- WeightedResponseTimeRule:對輪詢的擴展,響應速度越快的實例選擇權重越大,越容易被選擇
- BestAvailableRule:會先過濾掉由于多次訪問故障而處于斷路器跳閘狀態的服務,然后選擇一個并發量最小的服務
- AvailabiliyFilteringRule:先過濾掉故障實例,再選擇并發較小的實例
- ZoneAvoidanceRule:默認規則,復合判斷server所在區域的性能和server的可用性選擇服務器
IPing : 服務檢查
com.netflix.loadbalancer.IPing:
用于定期檢查 Server 的可用性的,它只提供了一個接口,用來判斷 Server 是否存活:
package com.netflix.loadbalancer;
public interface IPing {
boolean isAlive(Server var1);
}
- IPing 也提供了多種策略可選。


下面是整個 IPing 體系結構:

ServerList : 獲取服務列表
ServerList提供了2個接口: 一個是第一次獲取 Server 列表,一個是更新 Server 列表
其中 getUpdatedListOfServers 會每被 Loadbalancer 隔 30 秒調一次來更新 allServerList。
public interface ServerList<T extends Server> {
public List<T> getInitialListOfServers();
/**
* Return updated list of servers. This is called say every 30 secs
* (configurable) by the Loadbalancer's Ping cycle
*/
public List<T> getUpdatedListOfServers();
}
- ServerList 也提供了多種實現
ServerList 體系結構如下:


ServerListFilter : 過濾服務
ServerListFilter提供了一個接口用來過濾出可用的 Server。
public interface ServerListFilter<T extends Server> {
public List<T> getFilteredListOfServers(List<T> servers);
}

ServerListUpdater :服務列表更新
ServerListUpdater有多個接口,最核心的就是 start 開啟定時任務調用updateAction來更新allServerList。
public interface ServerListUpdater {
/**
* an interface for the updateAction that actually executes a server list update
*/
public interface UpdateAction {
void doUpdate();
}
/**
* start the serverList updater with the given update action
* This call should be idempotent.
*/
void start(UpdateAction updateAction);
}
- 默認有兩個實現類:

ILoadBalancer : 負載均衡器
ILoadBalancer是負載均衡選擇服務的核心接口,主要提供了如下的獲取Server列表和根據客戶端名稱選擇Server的接口。
public interface ILoadBalancer {
// 添加Server
public void addServers(List<Server> newServers);
// 根據key選擇一個Server
public Server chooseServer(Object key);
// 獲取存活的Server列表,返回 upServerList
public List<Server> getReachableServers();
// 獲取所有Server列表,返回 allServerList
public List<Server> getAllServers();
}

Z 案例實踐
CASE 實現客戶端式負載均衡器(快速入門版)
package com.knowdata.framework.study.ribbon.lb;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.RoundRobinRule;
import com.netflix.loadbalancer.Server;
/*
* @description Ribbon 負載均衡框架的快速入門示例
* @updateTime 2025/09/14 16:39
*/
public class RibbonQuickStartTest {
public static void main(String[] args) throws Exception {
// 定義目標服務器列表
List<Server> serverList = Arrays.asList(
new Server("localhost", 8086),
new Server("localhost", 8086),
new Server("localhost", 8086)
);
// 創建(客戶端式)負載均衡器
BaseLoadBalancer loadBalancer = new BaseLoadBalancer();
loadBalancer.setServersList(serverList);
// 配置負載均衡策略(可選,默認為輪詢)
loadBalancer.setRule(new RoundRobinRule());
// 其他策略示例:
// loadBalancer.setRule(new RandomRule());
// loadBalancer.setRule(new WeightedResponseTimeRule());
// 模擬多次請求,查看負載均衡效果
for (int i = 0; i < 10; i++) {
Server server = loadBalancer.chooseServer(null);
System.out.println("第 " + (i + 1) + " 次請求,選中服務器: " + server.getHostPort());
sendRequest(server);
}
}
private static void sendRequest(Server server) {
try {
URL url = new URL("http://" + server.getHost() + ":" + server.getPort() + "/api/hello");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
int responseCode = connection.getResponseCode();
System.out.println("響應碼: " + responseCode);
connection.disconnect();
} catch (IOException e) {
System.err.println("請求失敗: " + e.getMessage());
}
}
}
Y 推薦文獻
- Ribbon
X 參考文獻
本文鏈接: http://www.rzrgm.cn/johnnyzen
關于博文:評論和私信會在第一時間回復,或直接私信我。
版權聲明:本博客所有文章除特別聲明外,均采用 BY-NC-SA 許可協議。轉載請注明出處!
日常交流:大數據與軟件開發-QQ交流群: 774386015 【入群二維碼】參見左下角。您的支持、鼓勵是博主技術寫作的重要動力!

浙公網安備 33010602011771號