天天看點

【雲原生&微服務二】SpringCloud之Ribbon自定義負載均衡政策(含Ribbon核心API)

文章目錄

  • ​​一、前置知識​​
  • ​​二、Ribbon核心API​​
  • ​​三、自定義負載均衡政策IRule​​
  • ​​1、編寫IRule實作類​​
  • ​​2、編寫Ribbon配置類​​
  • ​​3、應用到全部服務上(Ribbon全局配置)​​
  • ​​1)Spring的自動掃描​​
  • ​​2)@RibbonClients注解​​
  • ​​3、應用到指定服務上(Ribbon局部配置)​​
  • ​​1)代碼配置 -- @RibbonClient​​
  • ​​2)屬性配置 -- application.yml​​
  • ​​3)兩種方式對比:​​
  • ​​4)**細粒度配置-最佳實踐:**​​
  • ​​4、使用浏覽器進行調用服務消費者​​
  • ​​四、自定義服務執行個體是否存活判定政策IPing​​
  • ​​1、自定義IPing​​
  • ​​2、修改Ribbon配置類​​
  • ​​五、性能優化-饑餓加載​​

一、前置知識

在前一篇文章​​【雲原生&微服務一】SpringCloud之Ribbon實作負載均衡詳細案例(內建Eureka、Ribbon)​​我們讨論了SpringCloud如何內建Eureka和Ribbon,本文就在其基礎上讨論一下如何自定義Ribbon的負載均衡政策、以及Ribbon的核心API。

二、Ribbon核心API

部落客習慣性的在深入研究一門技術的時候去GitHub上看文檔,然而Ribbon在GitHub上的文檔(​​https://github.com/Netflix/ribbon​​)真的是沒啥可看的;就給了一個demo和Release notes。

Ribbon有三個核心接口:ILoadBalancer、IRule、IPing,其中:

  1. ILoadBalancer是負載均衡器;
  2. 【雲原生&微服務二】SpringCloud之Ribbon自定義負載均衡政策(含Ribbon核心API)
  3. IRule 複雜負載均衡的規則,ILoadBalancer根據其選擇一個可用的Server伺服器;
  4. 【雲原生&微服務二】SpringCloud之Ribbon自定義負載均衡政策(含Ribbon核心API)
  5. IPing負責定時ping每個伺服器,判斷其是否存活。
  6. 【雲原生&微服務二】SpringCloud之Ribbon自定義負載均衡政策(含Ribbon核心API)

三、自定義負載均衡政策IRule

1、編寫IRule實作類

MyRule重寫IRule的​

​choose(Object o)​

​​方法,每次都通路​

​List<Server>​

​中第一個服務執行個體;

import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.Server;

import java.util.List;

/**
 * 自定義負載均衡規則,隻用第一個執行個體;
 *
 * @author Saint
 */
public class MyRule implements IRule {

    private ILoadBalancer loadBalancer;

    @Override
    public Server choose(Object o) {
        final List<Server> allServers = this.loadBalancer.getAllServers();
        return allServers.get(0);
    }

    @Override
    public void setLoadBalancer(ILoadBalancer iLoadBalancer) {
        this.loadBalancer = iLoadBalancer;
    }

    @Override
    public ILoadBalancer getLoadBalancer() {
        return loadBalancer;
    }
}      

注意:一般很少需要自己定制負載均衡算法的,除非是類似hash分發的那種場景,可以自己寫個自定義的Rule,比如說,每次都根據某個請求參數,分發到某台機器上去。不過在分布式系統中,盡量減少這種需要hash分發的情況。

下面我接着看如何把自定義的MyRule應用到指定的服務上 或 全部服務上。

2、編寫Ribbon配置類

在Ribbon配置類中通過@Bean注解将自定義的IRule實作類MyRule注入到Spring容器中。

import com.netflix.loadbalancer.IRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 自定義Ribbon配置
 *
 * @author Saint
 */
@Configuration
public class MyRibbonConfiguration {

    @Bean
    public IRule getRule() {
        return new MyRule();
    }
}      

3、應用到全部服務上(Ribbon全局配置)

Ribbon全局配置有兩種方式:一種是依賴Spring的自動掃描、一種是依賴​

​@RibbonClients​

​注解。

1)Spring的自動掃描

所謂Spring的自動掃描,就是将自定義的Ribbon配置類放在Spring容器可以掃描到的包目錄下即可。

【雲原生&amp;微服務二】SpringCloud之Ribbon自定義負載均衡政策(含Ribbon核心API)

如上圖所示,程式的啟動類RibbonFeignSampleConsumerApplication所在的目錄為com.saint,Ribbon配置類​

​MyRibbonConfiguration​

​ 所在的目錄為com.saint.config;又因沒有指定包掃描的路徑,是以目錄會掃描啟動類所在的包com.saint,是以Spring可以自動掃描到MyRibbonConfiguration、進而掃描到MyRule。

注意:Ribbon的配置類一定不能Spring掃描到。因為Ribbon有自己的子上下文,Spring的父上下文如果和Ribbon的子上下文重疊,會有各種各樣的問題。比如:Spring和SpringMVC父子上下文重疊會導緻事務不生效。

是以不推薦使用這種方式。

2)@RibbonClients注解

在啟動類所在目錄的父目錄(com.saint)中建立config檔案夾(com.config),并将​

​MyRibbonConfiguration​

​類移動到其中,代碼目錄結構如下:

【雲原生&amp;微服務二】SpringCloud之Ribbon自定義負載均衡政策(含Ribbon核心API)

這樣操作之後,Ribbon配置類講不會被Spring掃描到。是以需要利用​

​@RibbonClients​

​注解做一些配置;

在com.saint.config目錄下新增GreetingServiceRibbonConf類:

package com.saint.config;

import com.config.MyRibbonConfiguration;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.context.annotation.Configuration;

/**
 * @author Saint
 */
@Configuration
@RibbonClients(defaultConfiguration = MyRibbonConfiguration.class)
public class GreetingServiceRibbonConf {
}      

3、應用到指定服務上(Ribbon局部配置)

針對Ribbon局部配置,有兩種方式:代碼配置 和 屬性配置,上面提到的​

​@RibbonClients​

​​就屬于代碼配置的方式,差別在于Ribbon局部配置使用的是​

​@RibbonClient​

​注解;

1)代碼配置 – @RibbonClient

将GreetingServiceRibbonConf類的内容修改如下:

package com.saint.config;

import com.config.MyRibbonConfiguration;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.context.annotation.Configuration;

/**
 * 自定義 調用greeting-service服務時 使用的配置
 *
 * @author Saint
 */
@Configuration
@RibbonClient(name = "GREETING-SERVICE", configuration = MyRibbonConfiguration.class)
public class GreetingServiceRibbonConf {
}      

當然我們也可以不使用GreetingServiceRibbonConf作為一個配置類,直接将​

​@RibbonClient(name = "GREETING-SERVICE", configuration = MyRibbonConfiguration.class)​

​加在啟動類中也是一樣的。

2)屬性配置 – application.yml

首先将​

​GreetingServiceRibbonConf​

​類中的内容全部注釋掉:

【雲原生&amp;微服務二】SpringCloud之Ribbon自定義負載均衡政策(含Ribbon核心API)

然後在application.yml檔案中添加如下内容:

# GREETING-SERVICE為要調用的微服務名
GREETING-SERVICE:
  ribbon:
    NFLoadBalancerRuleClassName:      

3)兩種方式對比:

  • 代碼配置:基于代碼、更加靈活;但是線上修改得重新打包、釋出,并且還有小坑(父子上下文問題)
  • 屬性配置: 配置更加直覺、優先級更高(相對代碼配置)、線上修改無需重新打包、釋出;但是極端場景下沒有代碼配置方式靈活。

注意:如果代碼配置和屬性配置兩種方式混用,屬性配置優先級更高。

4)細粒度配置-最佳實踐:

  1. 盡量使用屬性配置,屬性方式實作不了的情況下再考慮代碼配置。
  2. 同一個微服務内盡量保持單一性,使用同樣的配置方式,避免兩種方式混用,增加定位代碼的複雜性。

4、使用浏覽器進行調用服務消費者

結合博文:​​【雲原生&微服務一】SpringCloud之Ribbon實作負載均衡詳細案例(內建Eureka、Ribbon)​​,我們已經依次啟動了eureka-server、ribbon-feign-sample-8081、ribbon-feign-sample-8082、ribbon-feign-sample-consumer;三個服務、四個執行個體。

此處我們針對服務消費者​

​ribbon-feign-sample-consumer​

​做四次接口調用,分别為:

  1. ​​http://localhost:9090/say/saint​​
  2. ​​http://localhost:9090/say/saint2​​
  3. ​​http://localhost:9090/say/saint3​​
  4. ​​http://localhost:9090/say/saint4​​
【雲原生&amp;微服務二】SpringCloud之Ribbon自定義負載均衡政策(含Ribbon核心API)

然後我們去看ribbon-feign-sample-8081、ribbon-feign-sample-8082的控制台輸出:1> ribbon-feign-sample-8081控制台輸出:

【雲原生&amp;微服務二】SpringCloud之Ribbon自定義負載均衡政策(含Ribbon核心API)

2> ribbon-feign-sample-8082控制台輸出:

【雲原生&amp;微服務二】SpringCloud之Ribbon自定義負載均衡政策(含Ribbon核心API)

3> 結果說明:

我們可以發現,四個請求,ribbon-feign-sample-8082執行個體處理了所有的請求,我們自定義的IRule已經生效。

四、自定義服務執行個體是否存活判定政策IPing

和IRule的自定義方式一樣,這裡隻提供自定義的IPing,具體配置方式和IRule一樣。

1、自定義IPing

package com.saint.config;

import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.Server;

/**
 * 自定義IPing,判斷每個服務是否還存活
 * @author Saint
 */
public class MyPing implements IPing {
    @Override
    public boolean isAlive(Server server) {
        return true;
    }
}      

2、修改Ribbon配置類

package com.config;

import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.IRule;
import com.saint.config.MyPing;
import com.saint.config.MyRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 自定義Ribbon配置
 *
 * @author Saint
 */
@Configuration
public class MyRibbonConfiguration {

    @Bean
    public IRule getRule() {
        return new MyRule();
    }

    @Bean
    public IPing getPing() {
        return new MyPing();
    }

}      

五、性能優化-饑餓加載

ribbon:
  eager-load:
    # 開啟饑餓加載
    enabled: true
    # 開啟饑餓加載的微服務清單,多個以,分隔
    clients: user-center,xxx      

繼續閱讀