微服務負載均衡器 Ribbon

HuDu發表於2022-01-13

一、什麼是 Ribbon

目前主流的負載均衡方案有以下兩種:

  • 集中式負載均衡,在消費者和服務提供方中間使用獨立的代理方式進行負載,有硬體的(比如 F5),也有軟體的(比如 Nginx)
  • 客戶端根據自己的請求情況負載均衡,Ribbon 就是屬於客戶端自己做負載均衡。

Spring Cloud Ribbon 是基於 Netflix Ribbon 實現的一套客戶端的負載均衡器工具,Ribbon 客戶端元件提供了一系列的完善的配置,如超時,重試等,通過 Load Balancer 獲取到服務提供的所有機器例項,Ribbon 會自動基於某種規則(輪詢,隨機)去呼叫這些服務。Ribbon 也可以實現我們自己的負載均衡演算法。

1.1、客戶端的負載均衡

例如 Spring Cloud 中的 Ribbon,客戶端會有一個伺服器地址列表,在傳送請求前通過負載均衡演算法選擇一個伺服器,然後進行訪問,這是客戶端負載均衡;即在客戶端就進行負載均衡演算法分配。

微服務負載均衡器 Ribbon

1.2、服務端的負載均衡

例如 Nginx,通過 Nginx 進行負載均衡,先傳送請求,然後通過負載均衡演算法,在多個伺服器之間選擇一個進行訪問;即在伺服器端再進行負載均衡演算法分配

微服務負載均衡器 Ribbon

1.3、常見負載均衡演算法

  • 隨機:通過隨機選擇伺服器進行執行,一般這種方式使用較少;
  • 輪訓:負載均衡預設實現方式,請求來之後排隊處理‘
  • 加權輪訓:通過對伺服器效能的分型,給高配置,低負載的伺服器分配更高的權重,均衡各個伺服器的壓力
  • 地址 Hash:通過客戶端請求的 Hash 值取模對映進行伺服器排程,IP Hash
  • 最小連結數:即使請求均衡了,壓力不一定會均衡,最小連線數法就是根據伺服器的情況,比如請求和積壓數等引數,將請求分配到當前壓力最小的伺服器上。

Nacos 使用 Ribbon

1、nacos-discovery 依賴了 ribbon,可以不再引入 ribbon依賴

微服務負載均衡器 Ribbon

2、新增 @LoadBalance

@Configuration
public class RestTemplateConfig {
    // 可以直接 new RestTemplate(),但是官方建議使用構造器
    @Bean
    @LoadBalanced // 相當於 RestTemplate 有了負載均衡的呼叫機制
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        RestTemplate restTemplate = builder.build();
        return restTemplate;
    }
}

3、修改 controller

@Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/add")
    public String add() {
        System.out.println("下單成功!");
        // restTemplate 呼叫
//        String message = restTemplate.getForObject("http://127.0.0.1:8021/stock/reduce", String.class);
        // 新增 @LoadBalance
        String message = restTemplate.getForObject("http://stock-server/stock/reduce", String.class);
        return "Hello World " + message;
    }

三、Ribbon 負載均衡策略

3.1、負載均衡策略

微服務負載均衡器 Ribbon

IRule

這是所有負載均衡策略的父介面,裡邊的核心方法就是 choose 方法,用來選擇一個服務例項。

AbstractLoadBalancerRule

AbstractLoadBalancerRule 是一個抽象類,裡邊主要定義了一個 ILoadBalancer,就是我們上文所說的負載均衡器,負載均衡器的功能我們在上文已經說的很清楚了,這裡它的目的主要是輔助負責均衡負載策略選取合適的服務端例項
  • RandomRule

    看名字就知道,這種負載均衡策略就是隨機選擇一個服務例項,看原始碼我們知道,在 RandomRule 的無參構造方法中初始化了一個 Random 物件,然後它重寫的 choose 方法又呼叫了 choose(ILoadBalancer Ib,Object key)這個過載的 choose 方法,在這個過載的 choose 方法中,每次利用 random 方法生成一個不再與服務例項總數的隨機數,並將該數作為下標以獲取一個服務例項
  • RoundRobinRule

    RoundRobinRule 這種負載均衡策略叫做線性輪詢負載均衡策略。這個類的 choose(ILoadBanancer Ib,Object key)函式整體邏輯是這樣的:開啟一個計數器 count,在 while 迴圈中遍歷服務清單,獲取清單之前通過 incrementGetModulo 方法獲取一個下表,這個下標是一個不斷自增長的數先加1然後和服務清單總數取模之後獲取到的(所以這個下標從來不會越界),拿著下標再去服務清單列表中取服務,每次迴圈計數器都會加1,如果連續10次都沒有取到服務,則會報一個警告No available alive servers after 10 tries from load balancer: XXXX
  • RertyRule(在輪詢的基礎上進行重試)

    看名字就知道這種負載均衡策略帶有重試功能。首先 RetryRule 中又定義了一個 subRule,它的實現類是 RoundRobinRule,然後在 RetryRule 的choose(ILoadBalancer Ib, Object key)方法中,每次還是採用RoundRobinRule中的choose規則來選擇一個服務例項, 如果選到的例項正常就返回,如果選擇的服務例項為null或者已經失效,則在失效時間 deadline 之 前不斷的進行重試(重試時獲取服務的策略還是RoundRobinRule中定義的策略),如果超過 了deadline還是沒取到則會返回一個null
  • WeightedResponseTimeRule(權重-nacos 的 NacosRule,Nacos 還擴充了一個自己的基於配置的權重擴充套件)

    WeightedResponseTimeRule是RoundRobinRule的一個子類,在WeightedResponseTimeRule中對RoundRobinRule的功能進行了擴充套件,WeightedResponseTimeRule中會根據每一個例項的執行情況來給計算出該例項的一一個權重,然後在挑選例項的時候則根據權重進行挑選,這樣能夠實現更優的例項呼叫。WeightedResponseTimeRule中有一 個名叫 DynamicServerWeightTask 的定時任務,預設情況下每隔30秒會計算一次各個服務例項的權重, 權重的計算規則也很簡單,如果一個服務的平均響應時間越短則權重越大,那麼該服務例項被選中執行任務的概率也就越大。
  • ClientConfigEnabledRoundRobinRule

    ClientConfigEnabledRoundRobinRule選擇策略的實現很簡單,內部定義了RoundRobinRule, choose方法還是採用了RoundRobinRule的choose方法,所以它的選擇策略和RoundRobinRule的選擇策略一致,不贅述。
  • BestAvailableRule

    BestAvailableRule繼承自ClientConfigEnabledRoundRobinRule,它在ClientConfigEnabledRoundRobinRule的基礎 上主要增加了根據loadBalancerStats中儲存的服務例項的狀態資訊來過濾掉失效的服務例項的功能,然後順便找出併發請求最小的服務例項來使用。然而loadBalancerStats有可能為null, 如果loadBalancerStats為null, 則BestAvailableRule將採用它的父類即ClientConfigEnabledRoundRobinRule的服務選取策略(線性輪詢)
  • ZoneAvoidanceRule(預設規則,符合判斷 server 所在區域的效能和 server 的可用性選擇伺服器)

    ZoneAvoidanceRule是PredicateBasedRule的一個實現類, 只不過這裡多一個過濾條件, ZoneAvoidanceRule中的過濾條件是以ZoneAvoidancePredicate為主過濾條件和以AvailabilityPredicate為次過濾條件組成的一個叫做CompositePredicate的組合過濾條件, 過濾成功之後,繼續採用線性輪詢(RoundRobinRule)的方式從過濾結果中選擇一個出來。
  • AvaliabilityFilteringRule(先過濾掉故障例項,再選擇併發較小的例項)

    過濾掉一直連線失敗的被標記為circuit tripped的後端Server,並過濾掉那些高併發的後端Server或者使用一個AvailbilityPredicate來包含過濾server的邏輯, 其實就是檢查status裡,記錄的各個Server的執行狀態。

3.2、修改預設的負載均衡策略

3.2.1、通過修改配置類的方式修改負載均衡策略

1、配置類:
注意這個配置類不能被 @SpringBootApplication 所在的包下,不能被其掃描到,不然配置全域性共享

微服務負載均衡器 Ribbon

@Configuration
public class RibbonRandomRuleConfig {

    /**
     * 方法名一定要叫 iRule
     * @return IRule
     */
    @Bean
    public IRule iRule() {
        // 配置隨機負載均衡策略
        return new RandomRule();
    }
}

2、在springboot入口類中新增註解

這裡的 stock-server 就是 Controller 裡呼叫的介面名稱

@SpringBootApplication
@RibbonClients(value = {
    @RibbonClient(name = "stock-server",configuration = RibbonRandomRuleConfig.class)
})
public class OrderRibbonServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderRibbonServerApplication.class,args);
    }
}

yml 配置如下

server:
  port: 8030
# 應用名稱(nacos 會自動將該名稱當作服務名稱)
spring:
  application:
    name: order-server
  cloud:
    nacos:
      server-addr: 127.0.0.1
      discovery:
        username: xxxxxx
        password: xxxxxx
        # 命名環境用來隔離服務
        namespace: public

3、啟動服務

將修改負載均衡策略為隨機的服務啟動,埠為 8030,啟動 stock-nacos 服務,埠為 80818082

4、請求測試

位址列輸入:http://localhost:8030/order/add
發現請求確到的服務確實是隨機的。

3.2.2 通過修改配置的方式

1、修改yml檔案

# 被呼叫的微服務名稱
stock-server:
  ribbon:
    # 指定使用 Nacos 提供的負載均衡策略(優先同一叢集的例項,機遇隨機&權重)
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule

2、修改服務的權重

微服務負載均衡器 Ribbon

3、測試生效

3.2.3、自定義負載均衡策略

通過實現 IRule 介面可以自定義負載均衡策略,主要的選擇服務邏輯在 choose 方法中。

1) 實現基於 Nacos 權重的負載均衡策略

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章