基於Spring Cloud和Netflix OSS構建微服務,Part 2

在上一篇文章中,咱們已使用Spring Cloud和Netflix OSS中的核心組件,如Eureka、Ribbon和Zuul,部分實現了操做模型(operations model),容許單獨部署的微服務相互通訊。在本文中,咱們繼續關注微服務環境中的故障處理,經過Hystrix(Netflix Circuit Breaker)提高服務彈性。html

 

如今咱們創建的系統開始出現故障,組合服務(composite service)依賴的部分核心服務忽然沒有反應,若是故障沒有正確處理,將進一步損害組合服務。java

 

一般,咱們將這一類問題稱爲失敗鏈(a chain of failures),一個組件中的錯誤將致使依賴於錯誤組件中的其餘組件也產生錯誤。在基於微服務的系統中,尤爲是大量獨立部署的微服務相互通訊,這一狀況須要特別關注。針對這一問題的通用解決方案是應用電路斷路器模式(circuit breaker pattern),詳細信息能夠查閱其餘文檔,或者閱讀Fowler-Circuit Breaker的文章。一個典型電路斷路器應用以下狀態轉換圖:git

(Source: Release It!) https://pragprog.com/book/mnee/release-itgithub

 

1. Spring Cloud和Netflix OSS

以下表所示,本文將包含:Hystrix、Hystrix dashboard和Turbine。spring

 

1/ Netflix Hystrix – 電路斷路器(Circuit Breaker)windows

Netflix Hystrix 對微服務消費方提供了電路斷路器功能。若是一個服務沒有響應(如超時或者網絡鏈接故障),Hystrix 能夠在服務消費方中重定向請求到回退方法(fallback method)。若是服務重複失敗,Hystrix 會打開電路,並快速失敗(如直接調用內部的回退方法,再也不嘗試調用服務),直到服務從新恢復正常。瀏覽器

 

爲了驗證是否服務再次恢復正常,即便在電路打開的狀況下,Hystrix 也會容許一部分請求再次調用微服務。Hystrix 是嵌入在服務調用方內部執行的。緩存

 

2/ Netflix Hystrix dashboard和Netflix Turbine –監控儀表盤(Monitor Dashboard)服務器

Hystrix儀表盤用來提供電路斷路器的圖形化視圖;Turbine 基於Eureka服務器的信息,獲取系統中全部電路斷路器的信息,提供給儀表盤。下圖是Hystrix儀表盤和Turbine工做視圖:網絡

2.  系統全貌

將前一部分Part 1實現的微服務系統,進一步添加支持性的基礎服務-Hystrix Dashboard和Turbine。另外,微服務product-composite也加強了基於Hystrix的電路斷路器。新增的2個組件標識爲紅色外框,以下圖所示:

 

在Part 1中,咱們重點強調了微服務和單體應用的差別,將每個微服務獨立部署運行(獨立進程)

 

3.  構建源代碼

在Part 1中,咱們使用Java SE 8,Git和Gradle工具。接下來訪問源代碼,並進行編譯:

$ git clone https://github.com/callistaenterprise/blog-microservices.git

$ cd blog-microservices

$ git checkout -b B2 M2.1

$ ./build-all.sh

 

若是運行在windows平臺,請執行相應的bat文件 – build-all.bat。

 

在Part 1源碼的基礎上,新增了2個源碼組件-monitor-dashboard和turbine:

 

編譯輸出8條log日誌:

BUILD SUCCESSFUL

 

 

4. 閱讀源代碼

和Part 1源代碼進行比較,本文在微服務product-composite中新增了Hystrix電路斷路器的使用。所以,咱們將關注電路斷路器部分新增的額外代碼。

 

4.1 Gradle依賴

如今,咱們在build文件中加入了幾個Hystrix相關的starter依賴。由於Hystrix使用RabbitMQ消息中間件在電路斷路器和儀表盤(dashboard)之間通訊,所以咱們也須要添加相應的依賴。

對於服務消費方,如須要使用Hystrix做爲電路斷路器,則須要添加以下依賴配置:

    compile("org.springframework.cloud:spring-cloud-starter-hystrix:1.0.0.RELEASE")

    compile("org.springframework.cloud:spring-cloud-starter-bus-amqp:1.0.0.RELEASE")

    compile("org.springframework.cloud:spring-cloud-netflix-hystrix-amqp:1.0.0.RELEASE")

 

更完整的示例,能夠查看product-composite-service/build.gradle文件。

爲了搭建Turbine 服務器,須要添加以下依賴:

    compile('org.springframework.cloud:spring-cloud-starter-turbine-amqp:1.0.0.RELEASE')

 

更完整的示例,能夠查看turbine/build.gradle文件。

 

4.2 基礎設施服務器

在標準的Spring Boot應用中,添加@EnableTurbineAmqp標註,就能夠搭建Turbine服務器了。

@SpringBootApplication

@EnableTurbineAmqp

@EnableDiscoveryClient

public class TurbineApplication {

 

    public static void main(String[] args) {

        SpringApplication.run(TurbineApplication.class, args);

    }

 

}

 

完整的示例,能夠查看TurbineApplication.java文件。

 

搭建Hystrix儀表盤,則須要添加@EnableHystrixDashboard標註。完整的示例,能夠查看HystrixDashboardApplication.java文件。

 

經過上述簡單的標註,就能夠得到默認服務器配置了。可根據須要使用特定的配置,覆蓋默認的配置。

 

4.3 業務服務

爲了啓用Hystrix,須要在Spring Boot應用中添加@EnableCircuitBreaker標註。爲了讓Hystrix真實地生效,還須要在Hystrix監控的方法上標註@HystrixCommand,在這個標註中,還能夠指定回退方法(fallback method),以下所示:

    @HystrixCommand(fallbackMethod = "defaultReviews")

    public ResponseEntity<List<Review>> getReviews(int productId) {

        ...

    }

 

    public ResponseEntity<List<Review>> defaultReviews(int productId) {

        ...

    }

 

在發生錯誤的時候(如調用服務失敗或者超時),Hystrix會調用回退方法;或者在電路打開的時候,進行快速失敗處理。完整的示例,能夠查看ProductCompositeIntegration.java文件。

5. 啓動系統

如前所述,Hystrix經過RabbitMQ消息中間件進行內部通訊,所以咱們在啓動微服務系統以前,須要先安裝並運行RabbitMQ。能夠訪問以下連接,瞭解RabbitMQ安裝教程:

https://www.rabbitmq.com/download.html

安裝完成以後,接着啓動RabbitMQ,經過運行RabbitMQ安裝目錄下的sbin子目錄中的rabbitmq-server程序進行啓動。

 

$ ~/Applications/rabbitmq_server-3.4.3/sbin/rabbitmq-server

 

              RabbitMQ 3.4.3. Copyright (C) 2007-2014 GoPivotal, Inc.

  ##  ##      Licensed under the MPL.  See http://www.rabbitmq.com/

  ##  ##

  ##########  Logs: /Users/magnus/Applications/rabbitmq_server-3.4.3/sbin/../var/log/rabbitmq/rabbit@Magnus-MacBook-Pro.log

  ######  ##        /Users/magnus/Applications/rabbitmq_server-3.4.3/sbin/../var/log/rabbitmq/rabbit@Magnus-MacBook-Pro-sasl.log

  ##########

              Starting broker... completed with 6 plugins.

 

如在windows系統中,確保RabbitMQ 服務已經啓動。

 

如今咱們準備好啓動系統了。使用./gradlew命令啓動每個微服務。

 

首先啓動基礎設施微服務:

$ cd support/discovery-server;  ./gradlew bootRun

$ cd support/edge-server;       ./gradlew bootRun

$ cd support/monitor-dashboard; ./gradlew bootRun

$ cd support/turbine;           ./gradlew bootRun

 

一旦上述服務啓動完成以後,接着啓動業務微服務:

$ cd core/product-service;                ./gradlew bootRun

$ cd core/recommendation-service;         ./gradlew bootRun

$ cd core/review-service;                 ./gradlew bootRun

$ cd composite/product-composite-service; ./gradlew bootRun

 

如在windows平臺,能夠執行相應的bat文件 – start-all.bat。

 

一旦微服務啓動完成,並註冊到服務發現服務器(Service Discovery Server),將同時輸出以下日誌:

DiscoveryClient ... - registration status: 204

和Part 1 同樣,咱們能夠在服務發現Web應用中看到以下4個業務服務和一個edge-server,以下所示(http://localhost:8761):

 

最後,驗證電路斷路器工做正常。在處於closed狀態時,經過edge-server訪問組合服務(composite service),輸出響應結果以下:

$ curl -s localhost:8765/productcomposite/product/1 | jq .

{

    "name": "name",

    "productId": 1,

    "recommendations": [

        {

            "author": "Author 1",

            "rate": 1,

            "recommendationId": 0

        },

        ...

    ],

    "reviews": [

        {

            "author": "Author 1",

            "reviewId": 1,

            "subject": "Subject 1"

        },

        ...

    ],

    "weight": 123

}

 

在瀏覽器中首先訪問http://localhost:7979 地址(Hystrix Dashboard),接着在文本框中輸入 http://localhost:8989/turbine.stream,並點擊Monitor Stream 按鈕:

 

咱們看到組合服務有3個電路斷路器正在運行中,分別是3個依賴的核心服務。目前都工做正常。接着,咱們準備嘗試故障測試,驗證電路斷路器發揮做用。

 

6. 發生故障

中止review微服務,再次嘗試以前的命令:

$ curl -s localhost:8765/productcomposite/product/1 | jq .

{

    "name": "name",

    "productId": 1,

    "recommendations": [

        {

            "author": "Author 1",

            "rate": 1,

            "recommendationId": 0

        },

        ...

    ],

    "reviews": null,

    "weight": 123

}

 

返回的響應報文中review部分是空的,可是其他部分報文保持不變。查看product-composite服務日誌,能夠發現以下警告信息:

2015-04-02 15:13:36.344  INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : GetRecommendations...

2015-04-02 15:13:36.497  INFO 29901 --- [teIntegration-2] s.c.m.c.p.s.ProductCompositeIntegration  : GetReviews...

2015-04-02 15:13:36.498  WARN 29901 --- [teIntegration-2] s.c.m.composite.product.service.Util     : Failed to resolve serviceId 'review'. Fallback to URL 'http://localhost:8081/review'.

2015-04-02 15:13:36.500  WARN 29901 --- [teIntegration-2] s.c.m.c.p.s.ProductCompositeIntegration  : Using fallback method for review-service

 

電路斷路器檢測到review服務發生了故障,將請求路由到服務消費方的回退方法(fallback method)。在本示例中,咱們只是簡單地返回一個null,但咱們也能夠返回一個本地緩存數據,以便在review服務發生故障時,提供更好的效果。

 

由於此時故障發生頻率並不高,所以電路仍然是閉合狀態(closed):

 

咱們接下來提升故障頻率,並超出Hystrix打開電路的限制,開始快速失敗。這裏,咱們使用Apache HTTP server benchmarking tool是實現這一目的:

ab -n 30 -c 5 localhost:8765/productcomposite/product/1

 

如今電路打開了:

 

隨後的請求將快速失敗,也就是說,電路斷路器將直接轉發請求到回退方法,再也不調用review服務。此時,log日誌中將再也不有GetReviews相關日誌。

2015-04-02 15:14:03.930  INFO 29901 --- [teIntegration-5] s.c.m.c.p.s.ProductCompositeIntegration  : GetRecommendations...

2015-04-02 15:14:03.984  WARN 29901 --- [ XNIO-2 task-62] s.c.m.c.p.s.ProductCompositeIntegration  : Using fallback method for review-service

 

然而,Hystrix不時地讓一部分請求經過電路,查看是否能夠調用成功,也就是檢查review服務是否再次恢復正常。咱們能夠屢次重複執行curl調用,查看product-composite服務的輸出日誌:

2015-04-02 15:17:33.587  INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : GetRecommendations...

2015-04-02 15:17:33.769  INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : GetReviews...

2015-04-02 15:17:33.769  WARN 29901 --- [eIntegration-10] s.c.m.composite.product.service.Util     : Failed to resolve serviceId 'review'. Fallback to URL 'http://localhost:8081/review'.

2015-04-02 15:17:33.770  WARN 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : Using fallback method for review-service

2015-04-02 15:17:34.431  INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : GetRecommendations...

2015-04-02 15:17:34.569  WARN 29901 --- [ XNIO-2 task-18] s.c.m.c.p.s.ProductCompositeIntegration  : Using fallback method for review-service

2015-04-02 15:17:35.209  INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : GetRecommendations...

2015-04-02 15:17:35.402  WARN 29901 --- [ XNIO-2 task-20] s.c.m.c.p.s.ProductCompositeIntegration  : Using fallback method for review-service

2015-04-02 15:17:36.043  INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : GetRecommendations...

2015-04-02 15:17:36.192  WARN 29901 --- [ XNIO-2 task-21] s.c.m.c.p.s.ProductCompositeIntegration  : Using fallback method for review-service

2015-04-02 15:17:36.874  INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : GetRecommendations...

2015-04-02 15:17:37.031  WARN 29901 --- [ XNIO-2 task-22] s.c.m.c.p.s.ProductCompositeIntegration  : Using fallback method for review-service

2015-04-02 15:17:41.148  INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : GetRecommendations...

2015-04-02 15:17:41.340  INFO 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : GetReviews...

2015-04-02 15:17:41.340  WARN 29901 --- [eIntegration-10] s.c.m.composite.product.service.Util     : Failed to resolve serviceId 'review'. Fallback to URL 'http://localhost:8081/review'.

2015-04-02 15:17:41.341  WARN 29901 --- [eIntegration-10] s.c.m.c.p.s.ProductCompositeIntegration  : Using fallback method for review-service

 

從log日誌的輸出中,咱們發現每5個調用,容許一次嘗試調用review服務(仍然沒有成功調用)。

如今,咱們再次啓動review服務,繼續嘗試調用組合服務product-composite。

備註:此時,你可能須要一點耐心(最多1分鐘)。在調用成功以前,須要服務發現服務器(Eureka)和動態路由(Ribbon)必須感知到review服務實例再次恢復可用。

如今,咱們看到返回結果正常了,review節點也恢復到返回報文中,電路也再次閉合(closed):

 

7. 總結

咱們已經看到了Netflix Hystrix如何用做電路斷路器(Circuit Breaker)有效地處理失敗鏈的問題。失敗鏈是指:當單個微服務故障時,因爲故障的擴散,會致使系統中大範圍微服務故障事故。幸好Spring Cloud框架提供的簡單標註和starter依賴,能夠很是容易在Spring環境中啓用Hystrix。最後,Hystrix dashboard和Turbine提供的儀表盤(Dashboard)功能,使得監控系統範圍內的大量電路斷路器變得切實可行。

 

8. 接下來

在構建微服務的下一篇文章中,咱們將學習如何使用OAuth 2.0 來限制對暴露爲外部API的微服務進行訪問。

 

英文原文連接:

Building microservices with Spring Cloud and Netflix OSS, part 2

相關連接:

基於Spring Cloud和Netflix OSS 構建微服務-Part 1

微服務操做模型

相關文章
相關標籤/搜索