spring cloud生態中Feign、Ribbon、loadbalancer的一些歷史

三國夢迴發表於2023-12-14

背景

本意是想寫個feign中loadbalancer元件和nacos相遇後,一個相容相關的問題,後面發現Feign這套東西很深,想一篇文章寫清楚很難,就先開一篇,講歷史。

Feign、OpenFeign、Spring Cloud OpenFeign

Feign

Feign是Java生態中的一個庫,這個庫的官方目標是:Feign makes writing Java http clients easier,大概就是讓http介面呼叫更加容易。

查了下歷史,最早是Netflix家的,座標如下,16年釋出了最後一個版本後停止維護:

<!-- https://mvnrepository.com/artifact/com.netflix.feign/feign-core -->
<dependency>
    <groupId>com.netflix.feign</groupId>
    <artifactId>feign-core</artifactId>
</dependency>

OpenFeign

2016年,Netflix將其捐贈給社群,改名OpenFeign,目前還一直在維護:

<dependency>
    <groupId>io.github.openfeig</groupId>
    <artifactId>feign-core</artifactId>
</dependency>

Spring Cloud OpenFeign

而Spring Cloud OpenFeign則是對Feign的整合,讓Feign能更方便地在spring專案中使用。

專案主頁:https://spring.io/projects/spring-cloud-openfeign#learn

Spring cloud這塊有兩個座標,一個是用於整合改名前的Feign,最早的版本是2015年,目前,這個座標早就標記為過期了,提示使用另一個: Spring Cloud Starter Feign (deprecated, please use spring-cloud-starter-openfeign)

https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-feign
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
    <version>1.0.0.RELEASE</version>
</dependency>

另一個則是整合改名後的OpenFeign,最早的版本是2017年11月20日,目前一直在維護,算是spring cloud中的核心元件:

<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>1.4.0.RELEASE</version>
</dependency>

值得一提的是,不管是哪一個座標,都是在第一個版本中,就已經依賴了ribbon這個元件,ribbon主要負責客戶端負載均衡,因為根據服務名從服務註冊中心會拿到很多例項,具體呼叫哪一個,就得靠ribbon這個元件來選擇其中一個,比如隨機、輪詢等演算法:

image-20231214210600179

spring-cloud-starter-openfeign:

image-20231214210651652

詳情可參考文章:https://juejin.cn/post/7097124836496900127

Feign使用示例

在feign中,比如要呼叫github的兩個介面,只需要向下面這樣定義好介面:

interface GitHub {
  @RequestLine("GET /repos/{owner}/{repo}/contributors")
  List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);

  @RequestLine("POST /repos/{owner}/{repo}/issues")
  void createIssue(Issue issue, @Param("owner") String owner, @Param("repo") String repo);
}

呼叫就像下面這樣:

// 發起呼叫,呼叫第一個介面
GitHub github = Feign.builder().target(GitHub.class, "https://api.github.com");
List<Contributor> contributors = github.contributors("OpenFeign", "feign");

可以看出,它的思路就是簡潔,就像呼叫普通的方法一樣,不用考慮序列化、反序列化、流的開啟和關閉、異常處理。

ribbon、spring cloud loadbalancer

我應該是18/19年開始在專案裡使用spring cloud,那時候的版本,還是spring cloud Netflix那一套,eureka + feign(ribbon) + hystrix斷路器 + zuul閘道器那一套,ribbon是由OpenFeign預設引入的。

後來,Netflix宣佈不再維護後,這一套中的元件,慢慢被替代。

前兩年在鵝廠沒搞spring cloud這一套,現在再搞這一套的時候,各個元件已經變天了。

在我們這,目前是,eureka變成了nacos,feign(ribbon)變成了feign(spring cloud loadbalancer),hystrix變成了sentinel,zuul閘道器變成了spring cloud gateway。

其中,feign是比較有意思的,之前的預設負載均衡元件是ribbon,但是ribbon因為也是Netflix家的,不再維護後,spring官方自己搞了個spring cloud loadbalancer。

spring cloud openfeign是從什麼時候開始支援自家的loadbalancer呢?我翻了下歷史,在2.1.5.RELEASE版本,都還只有ribbon(https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign/2.1.5.RELEASE)

下一個版本是2.2.0.RELEASE,已經開始支援loadbalancer了(https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-openfeign/2.2.0.RELEASE)。

當然,ribbon也還是支援的,只是多了個選擇。

image-20231214214228342

spring cloud loadbalancer的最早版本也就是2.2.0.RELEASE,想必就是為了和openfeign的版本保持一致。

ribbon落幕

我發現,OpenFeign目前主要有幾個大版本。

2.2.x(從2.2.0.RELEASE到從2.2.10.RELEASE),這個版本都是有ribbon的,當然也有loadbalancer;

3.0.x,該版本是不帶ribbon的,只有loadbalancer;

3.1.x,4.0.x,4.1.x,都是不帶ribbon的,只有loadbalancer。

理清歷史有什麼用

理清歷史,可以讓你對專案中的依賴和配置項更有掌控。

比如,ribbon和loadbalancer只需要一個就夠了,沒必要共存,那你會說,我肯定不會兩個依賴同時引入。

沒錯,但是ribbon可能作為如下依賴的間接依賴被引入:

<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-nacos-discovery -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2.2.9.RELEASE</version>
</dependency>

也就是說,nacos服務發現的2.2.x系列,預設引入ribbon。

image-20231214220634503

這樣的話,你就可以排除掉多餘的。

但你如果用的是nacos的2021.0.x系列,則它已經自己排除了ribbon系列,只支援loadbalancer了,就不需要手動排除了。

我就說我們有個專案很奇怪,為啥要手動排除ribbon:

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
                    <groupId>org.springframework.cloud</groupId>
                </exclusion>
            </exclusions>
        </dependency>

我才發現,是專案的nacos服務發現座標,從當時的2.2.x,升級到了:2021.0.5.0。我就說,排除個啥呀,本來都沒這個依賴。

另外,之前還需要手動禁用ribbon:

spring:
  cloud:
    loadbalancer:
      ribbon:
        enabled: false

沒理清楚這個歷史前,我還不敢去掉這段配置,現在呢,直接刪了就是。

這裡,總結一下,就是說,如果專案裡ribbon和loadbalancer共存,首先,這是沒啥必要的,其次,共存情況下要使用loadbalancer,則還是需要上面這段禁用ribbon的配置的。

參考文章

這篇是loadbalancer誕生的簡介。

https://spring.io/blog/2020/03/25/spring-tips-spring-cloud-loadbalancer

https://baijiahao.baidu.com/s?id=1662947934543573780

相關文章