Spring Cloud Ribbon 自定義負(fù)載均衡策略

原由

公司項(xiàng)目使用Spring Cloud微服務(wù)架構(gòu),隨著服務(wù)的增加,開發(fā)調(diào)試變得有些麻煩沧卢。有些同事的電腦配置不高,無法在本地啟動(dòng)這么多的服務(wù)醉者。公司有自己的dev環(huán)境搏恤,對(duì)于開發(fā)當(dāng)前修改的服務(wù)可以直接注冊(cè)到dev環(huán)境,使用其他未修改的服務(wù)湃交,如Eureka,config等藤巢。但是搞莺,如果這個(gè)時(shí)候有前端正在dev調(diào)試,則會(huì)出現(xiàn)網(wǎng)關(guān)轉(zhuǎn)發(fā)到本地開發(fā)中的服務(wù)掂咒,出現(xiàn)異常才沧。

出現(xiàn)上述情況的原因是因?yàn)镽ibbon默認(rèn)負(fù)載均衡策略是輪詢迈喉,當(dāng)一個(gè)服務(wù)出現(xiàn)多個(gè)實(shí)例的時(shí)候,網(wǎng)關(guān)轉(zhuǎn)發(fā)或者服務(wù)消費(fèi)時(shí)就會(huì)采用Ribbon的負(fù)載均衡策略温圆,出現(xiàn)指向開發(fā)本地實(shí)例的情況挨摸。

知道原因之后解決方法就呼之欲出了:自定義負(fù)載均衡策略,使dev環(huán)境中的微服務(wù)消費(fèi)或轉(zhuǎn)發(fā)都指定到固定dev環(huán)境中服務(wù)岁歉,不讓其指定到開發(fā)本地起的服務(wù)得运。

實(shí)現(xiàn)策略

com.netflix.loadbalancer.IRule是Ribbon的負(fù)載均衡策略接口:

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();    
}

Ribbon自帶有幾種策略實(shí)現(xiàn):

  • RandomRule:隨機(jī)選取負(fù)載均衡策略,隨機(jī)Random對(duì)象锅移,在所有服務(wù)實(shí)例中隨機(jī)找一個(gè)服務(wù)的索引號(hào)熔掺,然后從上線的服務(wù)中獲取對(duì)應(yīng)的服務(wù)。
  • RoundRobinRule:線性輪詢負(fù)載均衡策略非剃。
  • WeightedResponseTimeRule:響應(yīng)時(shí)間作為選取權(quán)重的負(fù)載均衡策略置逻,根據(jù)平均響應(yīng)時(shí)間計(jì)算所有服務(wù)的權(quán)重,響應(yīng)時(shí)間越短的服務(wù)權(quán)重越大备绽,被選中的概率越高券坞。剛啟動(dòng)時(shí),如果統(tǒng)計(jì)信息不足肺素,則使用線性輪詢策略恨锚,等信息足夠時(shí),再切換到WeightedResponseTimeRule压怠。
  • RetryRule:使用線性輪詢策略獲取服務(wù)眠冈,如果獲取失敗則在指定時(shí)間內(nèi)重試,重新獲取可用服務(wù)菌瘫。
  • ClientConfigEnabledRoundRobinRule:默認(rèn)通過線性輪詢策略選取服務(wù)蜗顽。通過繼承該類,并且對(duì)choose方法進(jìn)行重寫雨让,可以實(shí)現(xiàn)更多的策略雇盖,繼承后保底使用RoundRobinRule策略。
  • BestAvailableRule:繼承自ClientConfigEnabledRoundRobinRule栖忠。從所有沒有斷開的服務(wù)中崔挖,選取到目前為止請(qǐng)求數(shù)量最小的服務(wù)。
  • PredicateBasedRule:抽象類庵寞,提供一個(gè)choose方法的模板狸相,通過調(diào)用AbstractServerPredicate實(shí)現(xiàn)類的過濾方法來過濾出目標(biāo)的服務(wù),再通過輪詢方法選出一個(gè)服務(wù)捐川。
  • AvailabilityFilteringRule:按可用性進(jìn)行過濾服務(wù)的負(fù)載均衡策略脓鹃,會(huì)先過濾掉由于多次訪問故障而處于斷路器跳閘狀態(tài)的服務(wù),還有并發(fā)的連接數(shù)超過閾值的服務(wù)古沥,然后對(duì)剩余的服務(wù)列表進(jìn)行線性輪詢瘸右。
  • ZoneAvoidanceRule:本身沒有重寫choose方法娇跟,用的還是抽象父類PredicateBasedRule的choose。

其中沒有我們需要的策略太颤,那我們就自己實(shí)現(xiàn)一個(gè)IRule苞俘。我們參照默認(rèn)的RoundRobinRule,繼承AbstractLoadBalancerRule(實(shí)現(xiàn)了IRule的loadBanlancer相關(guān)方法):


import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @author hubert
 * @version 1.0
 * @date 2019/9/5 上午10:22
 */
@Slf4j
public class MyRule extends AbstractLoadBalancerRule {
    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {
    }

    @Override
    public Server choose(Object o) {
        log.info("key:" + o);
        List<Server> allServers = getLoadBalancer().getAllServers();
        log.info(allServers.toString());
        return allServers.get(0);
    }
}

我們需要實(shí)現(xiàn)choose方法來完成我們自己的策略龄章,getLoadBalancer()可以獲取當(dāng)前服務(wù)的所有實(shí)例Server的信息吃谣,我們需要從中挑選一個(gè)作為choose方法的返回。這里就簡(jiǎn)單地返回列表第一個(gè)Server瓦堵。

配置

自定義策略實(shí)現(xiàn)之后需要配置基协,我們要在服務(wù)調(diào)用方(使用@FeignClient注解的類的方法)進(jìn)行配置。

簡(jiǎn)單配置

如果所有調(diào)用服務(wù)的策略是相同的菇用,我們最簡(jiǎn)單的配置就是在MyRule類上添加@Component注解澜驮,讓Spring發(fā)現(xiàn)并注入該類。Ribbon會(huì)優(yōu)先使用我們實(shí)現(xiàn)的策略惋鸥。

如果針對(duì)不同的服務(wù)需要不同的策略杂穷,則可以參考官方實(shí)例的配置。

@RibbonClient配置

這種方式需要在啟動(dòng)類中添加注解:

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@RibbonClient(value = "service-hi", configuration = RuleConfig.class)
public class ServiceFeignApplication {

RuleConfig如下:

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

/**
 * @author hubert
 * @version 1.0
 * @date 2019/9/5 上午10:40
 */
@Configuration
public class RuleConfig {
    @Bean
    public IRule ribbonRule() {
        return new MyRule();
    }
}

簡(jiǎn)單來說就是注入我們自己實(shí)現(xiàn)的IRule卦绣,然后配置給RioonClient耐量。

@RibbonClientvalue/name屬性設(shè)置的是被調(diào)用的服務(wù)名(不是當(dāng)前正在配置的服務(wù)名),也即使聲明@FeignClient是指定的value/name滤港。如果當(dāng)前服務(wù)調(diào)用多個(gè)其他服務(wù)廊蜒,可以用@RibbonClient給每個(gè)被調(diào)用服務(wù)設(shè)置不同的策略。

需要注意的是RuleConfig類需要放在啟動(dòng)類的上層(或者不同包名)溅漾,避免Spring默認(rèn)掃描到山叮。否則會(huì)出現(xiàn)“簡(jiǎn)單配置”效果,即所有服務(wù)都使用這個(gè)策略添履,無法實(shí)現(xiàn)不同服務(wù)不同策略的效果屁倔。

配置文件配置

@RibbonClient類似,可以為每個(gè)微服務(wù)單獨(dú)配置策略暮胧。我們?cè)趛ml配置文件中添加<serverName>.ribbon.NFLoadBalancerRuleClassName

service-hi:
  ribbon:
    NFLoadBalancerRuleClassName: com.hubert.feign.MyRule

<serverName>也就是聲明@FeignClient是指定的value/name锐借。

實(shí)驗(yàn)

配置完成之后就是啟動(dòng)實(shí)驗(yàn)了,我們依次啟動(dòng)2個(gè)被調(diào)用服務(wù)往衷,以及一個(gè)調(diào)用服務(wù):

2019-09-05 14:31:45.408  INFO 1143 --- [ix-service-hi-2] com.hubert.feign.MyRule                  : key:null
2019-09-05 14:31:45.409  INFO 1143 --- [ix-service-hi-2] com.hubert.feign.MyRule                  : [192.168.31.244:8882, 192.168.31.244:8881]

發(fā)現(xiàn)日志打印钞翔,說明使用了我們自定義的策略,并且效果也是始終調(diào)用第一個(gè)服務(wù)席舍。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嗅战,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌驮捍,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件脚曾,死亡現(xiàn)場(chǎng)離奇詭異东且,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)本讥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門珊泳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人拷沸,你說我怎么就攤上這事色查。” “怎么了撞芍?”我有些...
    開封第一講書人閱讀 164,862評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵秧了,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我序无,道長(zhǎng)验毡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,728評(píng)論 1 294
  • 正文 為了忘掉前任帝嗡,我火速辦了婚禮晶通,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘哟玷。我一直安慰自己狮辽,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評(píng)論 6 392
  • 文/花漫 我一把揭開白布巢寡。 她就那樣靜靜地躺著喉脖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪讼渊。 梳的紋絲不亂的頭發(fā)上动看,一...
    開封第一講書人閱讀 51,590評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音爪幻,去河邊找鬼菱皆。 笑死,一個(gè)胖子當(dāng)著我的面吹牛挨稿,可吹牛的內(nèi)容都是我干的仇轻。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼奶甘,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼篷店!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,244評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤疲陕,失蹤者是張志新(化名)和其女友劉穎方淤,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蹄殃,經(jīng)...
    沈念sama閱讀 45,693評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡携茂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了诅岩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片讳苦。...
    茶點(diǎn)故事閱讀 40,001評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖吩谦,靈堂內(nèi)的尸體忽然破棺而出鸳谜,到底是詐尸還是另有隱情,我是刑警寧澤式廷,帶...
    沈念sama閱讀 35,723評(píng)論 5 346
  • 正文 年R本政府宣布咐扭,位于F島的核電站,受9級(jí)特大地震影響懒棉,放射性物質(zhì)發(fā)生泄漏草描。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評(píng)論 3 330
  • 文/蒙蒙 一策严、第九天 我趴在偏房一處隱蔽的房頂上張望穗慕。 院中可真熱鬧,春花似錦妻导、人聲如沸逛绵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽术浪。三九已至,卻和暖如春寿酌,著一層夾襖步出監(jiān)牢的瞬間胰苏,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工醇疼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留硕并,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,191評(píng)論 3 370
  • 正文 我出身青樓秧荆,卻偏偏與公主長(zhǎng)得像倔毙,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子乙濒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容