Ribbon源碼分析

介紹

先看下spring cloud官方對Ribbon的描述:Ribbon is a client-side load balancer that gives you a lot of control over the behavior of HTTP and TCP clients.
大意就是說拔疚,Ribbon是一個客戶端負責均衡器,它賦予了應(yīng)用一些支配HTTP與TCP行為的能力。那么,我們常見的nginx,lvs可以理解為服務(wù)端負載均衡滩届。在spring cloud中果正,F(xiàn)eign和Zuul中已經(jīng)默認集成了Ribbon贸毕。

Ribbon的負載均衡策略

負載均衡策略

開啟負載均衡

  • 直接在RestTemplate加上LoadBalance注解
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
    return new RestTemplate();
}
  • 第二種方式稍微麻煩一些
    在配置文件中加配置件蚕,hello-server是用來測試的兩個服務(wù),并注冊到eureka上
hello-server.ribbon.listOfServers=http://192.168.1.6:8101, http://192.168.1.6:8102

在啟動類上加注解

@RibbonClients(
        @RibbonClient(value = "hello-server")
)
@SpringBootApplication
@EnableCircuitBreaker
public class StudyApplication {

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

源碼解析

/**
 * Annotation to mark a RestTemplate bean to be configured to use a LoadBalancerClient.
 * @author Spencer Gibb
 */
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}

可以看到這個注解的注釋中明確的說道了RestTemplate配置使用LoadBalancerClient产禾,那么問題來了排作,LoadBalancerClient在哪,老套路亚情,我們還是去RibbonAutoConfiguration自動配置類看一下妄痪,在這個類里會看到這樣的代碼

@Bean
public SpringClientFactory springClientFactory() {
        SpringClientFactory factory = new SpringClientFactory();
        factory.setConfigurations(this.configurations);
        return factory;
}

這段代碼中會注入SpringClientFactory,可以猜測一下這個類作用楞件,用來獲取一個bean衫生,那么獲取什么樣的bean,我們往下看土浸。
在RibbonAutoConfiguration還有一個重要的bean罪针,LoadBalancerClient

@Bean
@ConditionalOnMissingBean(LoadBalancerClient.class)
    public LoadBalancerClient loadBalancerClient() {
        return new RibbonLoadBalancerClient(springClientFactory());
}

ok,可以清晰的看到這個SpringClientFactory會注入到LoadBalancerClient的實現(xiàn)類RibbonLoadBalancerClient中黄伊。
后面我們斷點跟進一下

@GetMapping("/study2")
public Object test2() {
    ServiceInstance serviceInstance = loadBalancerClient.choose("hello-server");
    String host = serviceInstance.getHost();
    int port = serviceInstance.getPort();
    return restTemplate.getForObject("http://" + host + ":" + port, String.class, "");
}

從這里進入choose方法最終會調(diào)用到RibbonLoadBalancerClient的如下方法

public ServiceInstance choose(String serviceId, Object hint) {
    Server server = getServer(getLoadBalancer(serviceId), hint);
    if (server == null) {
        return null;
    }
    return new RibbonServer(serviceId, server, isSecure(server, serviceId),
            serverIntrospector(serviceId).getMetadata(server));
}

進入getLoadBalancer()方法

protected ILoadBalancer getLoadBalancer(String serviceId) {
    return this.clientFactory.getLoadBalancer(serviceId);
}

這個clientFactory就是上面的SpringClientFactory泪酱,這里就明確了這個factory就是獲取ILoadBalancer的,獲得ILoadBalancer后还最,會獲取Server墓阀,那么繼續(xù)進入getServer()方法

protected Server getServer(ILoadBalancer loadBalancer, Object hint) {
    if (loadBalancer == null) {
        return null;
    }
    // Use 'default' on a null hint, or just pass it on?
    return loadBalancer.chooseServer(hint != null ? hint : "default");
}

負責均衡的目標就是幫我們選擇服務(wù),繼續(xù)進入chooseServer()方法拓轻,會進入到BaseLoadBalancer的chooseServer()方法

public Server chooseServer(Object key) {
    if (counter == null) {
        counter = createCounter();
    }
    counter.increment();
    if (rule == null) {
        return null;
    } else {
        try {
            return rule.choose(key);
        } catch (Exception e) {
            logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", name, key, e);
            return null;
        }
    }
}

在這我們會看到會用IRule選擇服務(wù)斯撮,所以IRule的實現(xiàn)類(默認是ZoneAvoidanceRule)會注入到ILoadBalancer中,分析到這里我們基本就明白了ribbon是如何選擇服務(wù)的扶叉。

總結(jié)

本文分析了如何選擇服務(wù)的源碼勿锅,實際上我們通過RestTemplate發(fā)起調(diào)用的時候,會通過攔截器攔截請求辜梳,選擇服務(wù)粱甫,再返回結(jié)果。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末作瞄,一起剝皮案震驚了整個濱河市茶宵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宗挥,老刑警劉巖乌庶,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件种蝶,死亡現(xiàn)場離奇詭異,居然都是意外死亡瞒大,警方通過查閱死者的電腦和手機螃征,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來透敌,“玉大人盯滚,你說我怎么就攤上這事⌒锏纾” “怎么了魄藕?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長撵术。 經(jīng)常有香客問我背率,道長,這世上最難降的妖魔是什么嫩与? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任寝姿,我火速辦了婚禮,結(jié)果婚禮上划滋,老公的妹妹穿的比我還像新娘饵筑。我一直安慰自己,他們只是感情好处坪,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布翻翩。 她就那樣靜靜地躺著,像睡著了一般稻薇。 火紅的嫁衣襯著肌膚如雪嫂冻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天塞椎,我揣著相機與錄音桨仿,去河邊找鬼。 笑死案狠,一個胖子當著我的面吹牛服傍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播骂铁,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼吹零,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拉庵?” 一聲冷哼從身側(cè)響起灿椅,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后茫蛹,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體操刀,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年婴洼,在試婚紗的時候發(fā)現(xiàn)自己被綠了骨坑。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡柬采,死狀恐怖欢唾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情粉捻,我是刑警寧澤匈辱,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站杀迹,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏押搪。R本人自食惡果不足惜树酪,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望大州。 院中可真熱鬧续语,春花似錦、人聲如沸厦画。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽根暑。三九已至力试,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間排嫌,已是汗流浹背畸裳。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留淳地,地道東北人怖糊。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像颇象,于是被迫代替她去往敵國和親伍伤。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355

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