天天看點

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

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

現在我們建立的系統開始出現故障,組合服務(composite service)依賴的部分核心服務突然沒有反應,如果故障沒有正确處理,将進一步損害組合服務。

通常,我們将這一類問題稱為失敗鍊(a chain of failures),一個元件中的錯誤将導緻依賴于錯誤元件中的其他元件也産生錯誤。在基于微服務的系統中,尤其是大量獨立部署的微服務互相通信,這一情況需要特别關注。針對這一問題的通用解決方案是應用電路斷路器模式(circuit breaker pattern),詳細資訊可以查閱其他文檔,或者閱讀Fowler-Circuit Breaker的文章。一個典型電路斷路器應用如下狀态轉換圖:

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

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

如下表所示,本文将包含:Hystrix、Hystrix dashboard和Turbine。

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

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

Netflix Hystrix 對微服務消費方提供了電路斷路器功能。如果一個服務沒有響應(如逾時或者網絡連接配接故障),Hystrix 可以在服務消費方中重定向請求到回退方法(fallback method)。如果服務重複失敗,Hystrix 會打開電路,并快速失敗(如直接調用内部的回退方法,不再嘗試調用服務),直到服務重新恢複正常。

為了驗證是否服務再次恢複正常,即使在電路打開的情況下,Hystrix 也會允許一部分請求再次調用微服務。Hystrix 是嵌入在服務調用方内部執行的。

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

Hystrix儀表盤用來提供電路斷路器的圖形化視圖;Turbine 基于Eureka伺服器的資訊,擷取系統中所有電路斷路器的資訊,提供給儀表盤。下圖是Hystrix儀表盤和Turbine工作視圖:

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

将前一部分Part 1實作的微服務系統,進一步添加支援性的基礎服務-Hystrix Dashboard和Turbine。另外,微服務product-composite也增強了基于Hystrix的電路斷路器。新增的2個元件辨別為紅色外框,如下圖所示:

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

在Part 1中,我們重點強調了微服務和單體應用的差異,将每一個微服務獨立部署運作(獨立程序)

在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:

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

編譯輸出8條log日志:

BUILD SUCCESSFUL

和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檔案。

如前所述,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/[email protected]

  ######  ##        /Users/magnus/Applications/rabbitmq_server-3.4.3/sbin/../var/log/rabbitmq/[email protected]

  ##########

              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):

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

最後,驗證電路斷路器工作正常。在處于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": [

            "reviewId": 1,

            "subject": "Subject 1"

    "weight": 123

在浏覽器中首先通路http://localhost:7979 位址(Hystrix Dashboard),接着在文本框中輸入 http://localhost:8989/turbine.stream,并點選Monitor Stream 按鈕:

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

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

停止review微服務,再次嘗試之前的指令:

    "reviews": null,

傳回的響應封包中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):

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

我們接下來提高故障頻率,并超出Hystrix打開電路的限制,開始快速失敗。這裡,我們使用Apache HTTP server benchmarking tool是實作這一目的:

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

現在電路打開了:

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

随後的請求将快速失敗,也就是說,電路斷路器将直接轉發請求到回退方法,不再調用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):

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

我們已經看到了Netflix Hystrix如何用作電路斷路器(Circuit Breaker)有效地處理失敗鍊的問題。失敗鍊是指:當單個微服務故障時,由于故障的擴散,會導緻系統中大範圍微服務故障事故。幸虧Spring Cloud架構提供的簡單标注和starter依賴,可以非常容易在Spring環境中啟用Hystrix。最後,Hystrix dashboard和Turbine提供的儀表盤(Dashboard)功能,使得監控系統範圍内的大量電路斷路器變得切實可行。

在建構微服務的下一篇文章中,我們将學習如何使用OAuth 2.0 來限制對暴露為外部API的微服務進行通路。

英文原文連結:

Building microservices with Spring Cloud and Netflix OSS, part 2

相關連結:

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

微服務操作模型

繼續閱讀