Spring Cloud 系列之 Netflix Ribbon 負載均衡

什麼是 Ribbon

Ribbon 是一個基於 HTTP 和 TCP 的 客服端負載均衡工具,它是基於 Netflix Ribbon 實現的。

它不像 Spring Cloud 服務註冊中心、配置中心、API 網關那樣獨立部署,但是它幾乎存在於每個 Spring Cloud 微服務中。包括 Feign 提供的聲明式服務調用也是基於該 Ribbon 實現的。

Ribbon 默認提供很多種負載均衡算法,例如輪詢、隨機等等。甚至包含自定義的負載均衡算法。

Ribbon 解決了什麼問題

Ribbon 提供了一套微服務的負載均衡解決方案。

負載均衡不同方案的區別

目前業界主流的負載均衡方案可分成兩類:

  • 集中式負載均衡(服務器負載均衡),即在 consumer 和 provider 之間使用獨立的負載均衡設施(可以是硬件,如 F5,也可以是軟件,如 nginx),由該設施負責把訪問請求通過某種策略轉發至 provider;
  • 進程內負載均衡(客戶端負載均衡),將負載均衡邏輯集成到 consumer,consumer 從服務註冊中心獲知有哪些地址可用,然後自己再從這些地址中選擇出一個合適的 provider。Ribbon 屬於後者,它只是一個類庫,集成於 consumer 進程,consumer 通過它來獲取 provider 的地址。

集中式負載均衡

進程內負載均衡

Ribbon 負載均衡策略

輪詢策略(默認)

策略對應類名:RoundRobinRule

實現原理:輪詢策略表示每次都順序取下一個 provider,比如一共有 5 個 provider,第 1 次取第 1 個,第 2 次取第 2 個,第 3 次取第 3 個,以此類推。

權重輪詢策略

策略對應類名:WeightedResponseTimeRule

實現原理:

  • 根據每個 provider 的響應時間分配一個權重,響應時間越長,權重越小,被選中的可能性越低。
  • 原理:一開始爲輪詢策略,並開啓一個計時器,每 30 秒收集一次每個 provider 的平均響應時間,當信息足夠時,給每個 provider 附上一個權重,並按權重隨機選擇 provider,高權越重的 provider 會被高概率選中。

隨機策略

策略對應類名:RandomRule

實現原理:從 provider 列表中隨機選擇一個。

最少併發數策略

策略對應類名:BestAvailableRule

實現原理:選擇正在請求中的併發數最小的 provider,除非這個 provider 在熔斷中。

重試策略

策略對應類名:RetryRule

實現原理:其實就是輪詢策略的增強版,輪詢策略服務不可用時不做處理,重試策略服務不可用時會重新嘗試集羣中的其他節點。

可用性敏感策略

策略對應類名:AvailabilityFilteringRule

實現原理:過濾性能差的 provider

  • 第一種:過濾掉在 Eureka 中處於一直連接失敗的 provider。
  • 第二種:過濾掉高併發(繁忙)的 provider。

區域敏感性策略

策略對應類名:ZoneAvoidanceRule

實現原理:

  • 以一個區域爲單位考察可用性,對於不可用的區域整個丟棄,從剩下區域中選可用的 provider。
  • 如果這個 ip 區域內有一個或多個實例不可達或響應變慢,都會降低該 ip 區域內其他 ip 被選中的權
    重。

Ribbon 入門案例

點擊鏈接觀看:Ribbon 入門案例視頻(獲取更多請關注公衆號「哈嘍沃德先生」)

eureka-demo 聚合工程。SpringBoot 2.2.4.RELEASESpring Cloud Hoxton.SR1

Ribbon 中對於集羣的服務採用的負載均衡策略默認是輪詢。

創建項目

使用學習 Eureka 時的 eureka-demo 項目,在該項目中創建子項目 service-provider02

添加依賴

pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>service-provider02</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 繼承父依賴 -->
    <parent>
        <groupId>com.example</groupId>
        <artifactId>eureka-demo</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <!-- 項目依賴 -->
    <dependencies>
        <!-- netflix eureka client 依賴 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- spring boot web 依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- lombok 依賴 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- spring boot actuator 依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!-- spring boot test 依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
  
</project>

配置文件

application.yml

server:
  port: 7071 # 端口

spring:
  application:
    name: service-provider # 應用名稱(集羣下相同)

# 配置 Eureka Server 註冊中心
eureka:
  instance:
    prefer-ip-address: true       # 是否使用 ip 地址註冊
    instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
  client:
    service-url:                  # 設置服務註冊中心地址
      defaultZone: http://root:123456@localhost:8761/eureka/,http://root:123456@localhost:8762/eureka/

# 度量指標監控與健康檢查
management:
  endpoints:
    web:
      exposure:
        include: shutdown         # 開啓 shutdown 端點訪問
  endpoint:
    shutdown:
      enabled: true               # 開啓 shutdown 實現優雅停服

服務及啓動類

將所有代碼複製粘貼一份至 server-provider02,修改啓動類名稱即可。

ServiceProvider02Application.java

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ServiceProvider02Application {

    public static void main(String[] args) {
        SpringApplication.run(ServiceProvider02Application.class, args);
    }

}

爲了更直觀的看到負載均衡的效果,我們在 service-consumer 項目中將服務地址打印至控制檯。

註冊中心

運行完整的 Eureka 環境,訪問:http://localhost:8761/ 可以看到現在已經有兩個服務提供者。

消費服務

多次訪問:http://localhost:9090/order/1 可以看到默認使用的是輪詢策略。

Ribbon 負載均衡策略設置

全局

在啓動類或配置類中注入負載均衡策略對象。所有服務請求均使用該策略。

@Bean
public RandomRule randomRule() {
    return new RandomRule();
}

多次訪問:http://localhost:9090/order/1 結果如下:

局部

修改配置文件指定服務的負載均衡策略。格式:服務應用名.ribbon.NFLoadBalancerRuleClassName

# 負載均衡策略
# service-provider 爲調用的服務的名稱
service-provider:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

多次訪問:http://localhost:9090/order/1 結果如下:

Ribbon 點對點直連

點擊鏈接觀看:Ribbon 點對點直連視頻(獲取更多請關注公衆號「哈嘍沃德先生」)

點對點直連是指繞過註冊中心,直接連接服務提供者獲取服務,一般在測試階段使用比較多。

添加依賴

在 pom 文件中引入 Ribbon,需要注意的是如果 pom 中有 Eureka 的依賴,則需要去除 Eureka 的依賴。

<!-- netflix ribbon 依賴 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

配置文件

配置文件中關閉 Eureka,添加直連的服務地址。如果不設置負載均衡策略默認使用輪詢策略。

# 負載均衡策略
# service-provider 爲調用的服務的名稱
service-provider:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
    # 指定具體的 Provider 服務列表,多個用逗號隔開
    listOfServers: http://localhost:7070,http://localhost:7071

# 關閉 Eureka 實現 Ribbon 點對點直連
ribbon:
  eureka:
    enabled: false # false:關閉,true:開啓

訪問

關閉 Eureka 註冊中心,服務提供者由於無法連接至註冊中心所以會報連接異常。但是服務是可以正常可消費的,所以目前使用的是點對點的方式來進行調用的。

多次訪問:http://localhost:9090/order/1 結果如下:

至此 Ribbon 負載均衡所有的知識點就講解結束了。

本文采用 知識共享「署名-非商業性使用-禁止演繹 4.0 國際」許可協議

大家可以通過 分類 查看更多關於 Spring Cloud 的文章。


🤗 您的點贊轉發是對我最大的支持。

📢 掃碼關注 哈嘍沃德先生「文檔 + 視頻」每篇文章都配有專門視頻講解,學習更輕鬆噢 ~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章