Spring Cloud升級之路 - Hoxton - 1.背景介紹與要實現的功能

本系列示例與膠水代碼地址: https://github.com/HashZhang/spring-cloud-scaffold

Spring Cloud還是比較活躍的,更新一直很快。我一般考慮最新版本SR2發佈之後,再考慮升級(一般SR1還有SR2會有一些新老框架的兼容性升級)。而且由於需要我們線上穩定,結合我們的發佈週期來看,跳一個大版本升級是一個更好的選擇(也就是一年做一次大版本升級)。例如我們之前的升級路線就是:Brixton -> Daltson -> Finchley -> 當前的Hoxton

做了這麼多次升級,感覺可以出這個系列,來分享我們項目使用Spring cloud框架實現的框架功能,在升級中遇到的坑,以及如何升級等等。每個版本都會有實例代碼,並在上一版本實現的功能基礎上,實現更多更實用的功能。所有示例代碼都在開頭提到的項目中,每個版本系列的最後,還會附上功能測試流程。

在Hoxton版本Release的同時,Spring Cloud也宣佈,其中的這些項目,已經進入維護模式(不再開發新功能),用戶最好做如下的替換:

  • Spring Cloud Netflix Ribbon -> Spring Cloud Load Balancer
  • Spring Cloud NetFlix Zuul -> Spring Cloud Gateway
  • Spring Cloud Hystrix -> Spring Cloud Circuit Breaker + Resilience4J
  • Spring Cloud Netflix Turbine -> Micrometer + Promethus
  • Spring Cloud Netflix Archaius -> Spring Cloud Config Server

可以看出,Spring Cloud netflix中的zuul, ribbon, hystrix都基本上算是廢了,我們也可以拋棄掉Sprnig Cloud Netflix了。還有一個體系也在官方中,就是Spring Cloud Alibaba,但是通過Spring Cloud netflix這件事,我個人感覺這種依賴性質的膠水項目,最好還是我們架構組自己維護,這塊是比較容易有坑的,自己維護自己用更新起來更高效,而且不會有粘合的項目都不更新了替換起來要人命的代價。

Spring Cloud Hoxton,至少對於官方文檔來說,是一個里程碑式的變化。官方文檔終於將所有項目的文檔分開了,並且做了比較多的整理,可以看出,這個Hoxton一定是有人下定決心要做一個變革了。並且,Spring Cloud在這個版本引入了更多的虛擬化,雲原生依賴,例如Spring-Cloud-kubernetes,確實,有些服務發現,調用策略什麼的,Spring Cloud和k8s體系重複了,這個依賴可以使我們靈活地切換這些功能到底交給誰來做,期待這個項目的完善成熟。

這篇文章,會主要列出升級步驟與詳細說明,以及對應的源代碼,和實現的功能。以及如何替換Spring Cloud Netflix體系爲新的組件。

原有的功能以及之前的實現

1. 微服務

以前的體系:

  1. 註冊中心:Eureka
  2. 客戶端封裝:OpenFeign
  3. 客戶端負載均衡:Ribbon
  4. 斷路器與隔離: Hystrix

實現的功能:

  1. 所有集羣公用同一個公共Eureka集羣,集羣之間不互相調用,通過實例的metamap中的zone配置,來區分不同集羣的實例。之前通過Ribbon的配置ServerListFilter實現,使用com.netflix.loadbalancer.ZoneAffinityServerListFilter作爲ServerListFilter,參考:Spring cloud實現FeignClient指定Zone調用
  2. 微服務之間調用,有重試,只對GET請求進行重試,連接超時,讀取超時還有 4xx 和 5xx 的狀態碼都會重試。這個之前是通過加入spring-retry重試通過ribbon配置實現的。參考:Spring Cloud Finchley OpenFeign的重試配置相關的坑
  3. 微服務調用有線程隔離,例如微服務1調用微服務2和微服務3,調用微服務2的線程和微服務3的線程不一樣。之前是通過Hystrix配置實現hystrix.threadpool.default.coreSize=50
  4. 實現了實例級別的熔斷,而不是微服務級別的。當調用微服務的兩個實例的時候,當一個實例一直異常,則將這個實例斷路器打開一段時間,而不是整個微服務都不能工作。之前通過Ribbon的配置LoadBalancerRule實現,使用com.netflix.loadbalancer.AvailabilityFilteringRule作爲LoadBalancerRule。參考:Ribbon的AvailabilityFilteringRule的坑

2. 網關

以前的體系:

  1. API網關:Zuul

實現的功能:

  1. 重試,只對GET請求進行重試,連接超時,讀取超時還有 4xx 和 5xx 的狀態碼都會重試。這個之前是通過加入spring-retry重試通過ribbon配置實現的。
  2. 微服務調用有線程隔離,例如微服務1調用微服務2和微服務3,調用微服務2的線程和微服務3的線程不一樣。之前是通過Hystrix配置實現hystrix.threadpool.default.coreSize=50
  3. 實現了實例級別的熔斷,而不是微服務級別的。當調用微服務的兩個實例的時候,當一個實例一直異常,則將這個實例斷路器打開一段時間,而不是整個微服務都不能工作。之前通過Ribbon的配置LoadBalancerRule實現,使用com.netflix.loadbalancer.AvailabilityFilteringRule作爲LoadBalancerRule。參考:Ribbon的AvailabilityFilteringRule的坑
  4. 特定接口 request body 解密與特定接口 response body 的加密。

3. Eureka-Server

實現的功能:

  1. 實例的快速上線下線,參考:Eureka 服務實例實現快速下線快速感知快速刷新配置解析

現在要實現的功能

1. 微服務

  1. 微服務之間調用依然基於利用 open-feign 的方式,有重試,僅對GET請求並且狀態碼爲4xx和5xx進行重試(對4xx重試是因爲滾動升級的時候,老的實例沒有新的 api,重試可以將請求發到新的實例上)
  2. 某個微服務調用其他的微服務 A 和微服務 B, 調用 A 和調用 B 的線程池不一樣。並且調用不同實例的線程池也不一樣。也就是實例級別的線程隔離
  3. 實現實例級別的熔斷。
  4. 使用 zone 隔離,不同 zone 之間不能互相調用
  5. 負載均衡的輪詢算法,需要請求與請求之間隔離,不能共用同一個 position 導致某個請求失敗之後的重試還是原來失敗的實例

2. 網關

  1. 轉發請求,有重試,僅對GET請求並且狀態碼爲4xx和5xx進行重試
  2. 不同微服務的不同實例線程隔離
  3. 實現實例級別的熔斷。
  4. 使用 zone 隔離,僅轉發請求到同 zone 的實例
  5. 負載均衡的輪詢算法,需要請求與請求之間隔離,不能共用同一個 position 導致某個請求失敗之後的重試還是原來失敗的實例

3. Eureka

  1. 實現服務實例快速上下線

新的pom依賴

1. 微服務

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.7.RELEASE</version>
    </parent>

    <properties>
        <disruptor.version>3.4.2</disruptor.version>
        <resilience4j-spring-cloud2.version>1.1.0</resilience4j-spring-cloud2.version>
    </properties>

    <dependencies>
        <!--內部緩存框架統一採用caffeine-->
        <!--這樣Spring cloud loadbalancer用的本地實例緩存也是基於Caffeine-->
        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
        </dependency>

        <!--日誌需要用log4j2-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>

        <!--lombok簡化代碼-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!--註冊到eureka-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <!--spring cloud rpc相關-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--調用路徑記錄-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-sleuth</artifactId>
        </dependency>
        <!--暴露actuator相關端口-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--暴露http接口, servlet框架採用nio的undertow,注意直接內存使用,減少GC-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-undertow</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>
        <dependency>
            <groupId>io.github.resilience4j</groupId>
            <artifactId>resilience4j-spring-cloud2</artifactId>
            <version>${resilience4j-spring-cloud2.version}</version>
        </dependency>
        <!--log4j2異步日誌需要的依賴,所有項目都必須用log4j2和異步日誌配置-->
        <dependency>
            <groupId>com.lmax</groupId>
            <artifactId>disruptor</artifactId>
            <version>${disruptor.version}</version>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR4</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.1</version>
                <configuration>
                    <!--最好用JDK 12版本及以上編譯,11.0.7對於spring-cloud-gateway有時候編譯會有bug-->
                    <!--雖然官網說已解決,但是11.0.7還是偶爾會出現-->
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

2. 網關

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.7.RELEASE</version>
    </parent>

    <properties>
        <disruptor.version>3.4.2</disruptor.version>
        <resilience4j-spring-cloud2.version>1.1.0</resilience4j-spring-cloud2.version>
    </properties>

    <dependencies>
        <!--內部緩存框架統一採用caffeine-->
        <!--這樣Spring cloud loadbalancer用的本地實例緩存也是基於Caffeine-->
        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
        </dependency>
        <!--日誌需要用log4j2-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
        <!--lombok簡化代碼-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--調用路徑記錄-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-sleuth</artifactId>
        </dependency>
        <!--暴露actuator相關端口-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>io.github.resilience4j</groupId>
            <artifactId>resilience4j-spring-cloud2</artifactId>
            <version>${resilience4j-spring-cloud2.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
        </dependency>
        <!--log4j2異步日誌需要的依賴,所有項目都必須用log4j2和異步日誌配置-->
        <dependency>
            <groupId>com.lmax</groupId>
            <artifactId>disruptor</artifactId>
            <version>${disruptor.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.1</version>
                <configuration>
                    <!--最好用JDK 12版本及以上編譯,11.0.7對於spring-cloud-gateway有時候編譯會有bug-->
                    <!--雖然官網說已解決,但是11.0.7還是偶爾會出現-->
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR4</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

3. Eureka-Server

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.7.RELEASE</version>
    </parent>

    <properties>
        <disruptor.version>3.4.2</disruptor.version>
    </properties>

    <dependencies>
        <!--內部緩存框架統一採用caffeine-->
        <!--這樣Spring cloud loadbalancer用的本地實例緩存也是基於Caffeine-->
        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
        </dependency>

        <!--日誌需要用log4j2-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>

        <!--lombok簡化代碼-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!--調用路徑記錄-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-sleuth</artifactId>
        </dependency>
        <!--暴露actuator相關端口-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--暴露http接口, servlet框架採用nio的undertow,注意直接內存使用,減少GC-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-undertow</artifactId>
        </dependency>
        <!--log4j2異步日誌需要的依賴,所有項目都必須用log4j2和異步日誌配置-->
        <dependency>
            <groupId>com.lmax</groupId>
            <artifactId>disruptor</artifactId>
            <version>${disruptor.version}</version>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR4</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.6.1</version>
                <configuration>
                    <!--最好用JDK 12版本及以上編譯,11.0.7對於spring-cloud-gateway有時候編譯會有bug-->
                    <!--雖然官網說已解決,但是11.0.7還是偶爾會出現-->
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章