1. 程式人生 > 其它 >Spring Cloud Ribbon

Spring Cloud Ribbon

簡介

​ Spring Cloud Ribbon是一個基於HTTP和TCP的客戶端負載均衡工具,它基於Netflix Ribbon實現。通過Spring Cloud的封裝,可以讓我們輕鬆地將面向服務的REST模版請求自動轉換成客戶端負載均衡的服務呼叫。Spring Cloud Ribbon雖然只是一個工具類框架,它不像服務註冊中心、配置中心、API閘道器那樣需要獨立部署,但是它幾乎存在於每一個Spring Cloud構建的微服務和基礎設施中。因為微服務間的呼叫,API閘道器的請求轉發等內容,實際上都是通過Ribbon來實現的,包括後續我們將要介紹的Feign,它也是基於Ribbon實現的工具。所以,對Spring Cloud Ribbon的理解和使用,對於我們使用Spring Cloud來構建微服務非常重要。Ribbon預設為我們提供了很多負載均衡演算法,例如輪詢、隨機等。當然,我們也可為Ribbon實現自定義的負載均衡演算法。

Ribbon的負載均衡應用在以下幾方面:

  • RestTemplate
  • Feign
  • Zuul

Ribbon實現軟負載均衡有三點:

  • 服務發現

    發現依賴服務的列表,依據服務的名字,把該服務所有的例項找到。

  • 服務選擇規則

    依據規則策略,如何從多個服務中選擇一個有效的服務

  • 服務監聽

    檢測失效的服務,做到高效剔除

Ribbon的主要元件包括:

  • ServerList
  • IRule
  • ServerListFilter

​ 首先通過ServerList獲取所有可用服務列表,然後通過ServerListFilter過濾掉一部分地址,最後剩下的地址中,使用IRule選擇一個例項作為最終目標結果。

負載均衡有好幾種實現策略,常見的有:

  1. 隨機 (Random)
  2. 輪詢 (RoundRobin)
  3. 一致性雜湊 (ConsistentHash)
  4. 雜湊 (Hash)
  5. 加權(Weighted)

ILoadBalance 負載均衡器

​ Ribbon內部提供了一個叫做ILoadBalance的介面代表負載均衡器的操作,其中包括新增伺服器操作選擇伺服器操作獲取所有的伺服器列表獲取可用的伺服器列表等。

ILoadBalance的繼承關係如下:

​ 負載均衡器是從EurekaClient(EurekaClient的實現類為DiscoveryClient)獲取服務資訊,根據IRule去路由,並且根據IPing判斷服務的可用性。在BaseLoadBalancer類下,BaseLoadBalancer的建構函式,該建構函式開啟了一個PingTask任務setupPingTask();,程式碼如下:

public BaseLoadBalancer(String name, IRule rule, LoadBalancerStats stats,
            IPing ping, IPingStrategy pingStrategy) {
    logger.debug("LoadBalancer [{}]:  initialized", name);

    this.name = name;
    this.ping = ping;
    this.pingStrategy = pingStrategy;
    setRule(rule);
    setupPingTask();
    lbStats = stats;
    init();
}

setupPingTask方法開啟了ShutdownEnabledTimer執行PingTask任務,在預設情況下pingIntervalSeconds為10,即每10秒鐘,向EurekaClient傳送一次”ping”,並有可能從Eureka Client獲取註冊資訊。針對PingTask,它根據pingerStrategy.pingServers(ping, allServers)來獲取服務的可用性,如果該返回結果,如之前相同,則不去向EurekaClient獲取註冊列表,如果不同則通知ServerStatusChangeListener或者changeListeners發生了改變,進行更新或者重新拉取。

class PingTask extends TimerTask {
    public void run() {
        try {
            new Pinger(pingStrategy).runPinger();
        } catch (Exception e) {
            logger.error("LoadBalancer [{}]: Error pinging", name, e);
        }
    }
}
void setupPingTask() {
    if (canSkipPing()) {
        return;
    }
    if (lbTimer != null) {
        lbTimer.cancel();
    }
    lbTimer = new ShutdownEnabledTimer("NFLoadBalancer-PingTimer-" + name,true);
    lbTimer.schedule(new PingTask(), 0, pingIntervalSeconds * 1000);
    forceQuickPing();
}

如果可用性改變後,重新拉取了註冊中心的資料,LoadBalancerClient有了這些服務註冊的新列表,就可以根據具體的IRule來進行負載均衡。

IRule 路由

IRule介面代表負載均衡策略:

public interface IRule{
    /*
     * choose one alive server from lb.allServers or
     * lb.upServers according to key
     * 
     * @return choosen Server object. NULL is returned if none
     *  server is available 
     */

    public Server choose(Object key);
    
    public void setLoadBalancer(ILoadBalancer lb);
    
    public ILoadBalancer getLoadBalancer();    
}

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

全域性配置

  • 配置類方式
@Configuration
public class RibbonGlobalLoadBalancingConfiguration {
    /**
     * 隨機規則
     */
    @Bean
    public IRule ribbonRule() {
        return new RandomRule();
    }
}

指定服務配置

  • 註解方式

增加一個針對單個服務的 Ribbon 負載聚恆策略配置類:

@Configuration
//標記使用的註解
@AvoidScan
public class RibbonRandomLoadBalancingConfiguration {

    //針對客戶端的配置管理器。
    @Resource
    IClientConfig clientConfig;

    @Bean
    public IRule ribbonRule(IClientConfig clientConfig) {
        return new RandomRule();
    }

}

啟動類上加入針對單個服務的負載均衡策略:

/** 配置針對單個服務的 Ribbon 負載均衡策略 **/
@RibbonClient(
    name = "users", configuration = RibbonRandomLoadBalancingConfiguration.class
)
/** 此處配置根據標識 @AvoidScan 過濾掉需要單獨配置的 Ribbon 負載均衡策略,不然就會作用於全域性,啟動就會報錯 */
@ComponentScan(
        excludeFilters = @ComponentScan.Filter(
                type = FilterType.ANNOTATION, value = AvoidScan.class
        )
)
public class UsersApplication {

	public static void main(String[] args) {
		SpringApplication.run(UsersApplication.class, args);
	}
}
  • 配置檔案方式(推薦)

application.yml.

users:#服務名稱
  ribbon:
    NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule