Spring Cloud Hystrix應用篇(十一)

童話述說我的結局發表於2021-01-02

一、背景

分散式系統環境下,服務間類似依賴非常常見,一個業務呼叫通常依賴多個基礎服務。如下圖,對於同步呼叫,當庫存服務不可用時,商品服務請求執行緒被阻塞,當有大批量請求呼叫庫存服務時,最終可能導致整個商品服務資源耗盡,無法繼續對外提供服務。並且這種不可用可能沿請求呼叫鏈向上傳遞,這種現象被稱為雪崩效應。

 

二、雪崩效應常見場景

  • 硬體故障:如伺服器當機,機房斷電,光纖被挖斷等。
  • 流量激增:如異常流量,重試加大流量等。
  • 快取穿透:一般發生在應用重啟,所有快取失效時,以及短時間內大量快取失效時。大量的快取不命中,使請求直擊後端服務,造成服務提供者超負荷執行,引起服務不可用。
  • 程式BUG:如程式邏輯導致記憶體洩漏,JVM長時間FullGC等。
  • 同步等待:服務間採用同步呼叫模式,同步等待造成的資源耗盡。

三、雪崩效應應對策略

針對造成雪崩效應的不同場景,可以使用不同的應對策略,沒有一種通用所有場景的策略,參考如下:

  • 硬體故障:多機房容災、異地多活等。
  • 流量激增:服務自動擴容、流量控制(限流、關閉重試)等。
  • 快取穿透:快取預載入、快取非同步載入等。
  • 程式BUG:修改程式bug、及時釋放資源等。
  • 同步等待:資源隔離、MQ解耦、不可用服務呼叫快速失敗等。資源隔離通常指不同服務呼叫採用不同的執行緒池;不可用服務呼叫快速失敗一般通過熔斷器模式結合超時機制實現。

綜上所述,如果一個應用不能對來自依賴的故障進行隔離,那該應用本身就處在被拖垮的風險中。 因此,為了構建穩定、可靠的分散式系統,我們的服務應當具有自我保護能力,當依賴服務不可用時,當前服務啟動自我保護功能,從而避免發生雪崩效應。本文將重點介紹使用Hystrix解決同步等待的雪崩問題。

 四、什麼是Hystrix

在分散式環境中,許多服務依賴項中的一些必然會失敗。Hystrix是一個庫,通過新增延遲容忍和容錯邏輯,幫助你控制這些分散式服務之間的互動。Hystrix通過隔離服務之間的訪問點、停止級聯失敗和提供回退選項來實現這一點,所有這些都可以提高系統的整體彈性。

Hystrix設計目標:

  • 對來自依賴的延遲和故障進行防護和控制——這些依賴通常都是通過網路訪問的
  • 阻止故障的連鎖反應
  • 快速失敗並迅速恢復
  • 回退並優雅降級
  • 提供近實時的監控與告警

Hystrix遵循的設計原則:

  • 防止任何單獨的依賴耗盡資源(執行緒)
  • 過載立即切斷並快速失敗,防止排隊
  • 儘可能提供回退以保護使用者免受故障
  • 使用隔離技術(例如隔板,泳道和斷路器模式)來限制任何一個依賴的影響
  • 通過近實時的指標,監控和告警,確保故障被及時發現
  • 通過動態修改配置屬性,確保故障及時恢復
  • 防止整個依賴客戶端執行失敗,而不僅僅是網路通訊

Hystrix如何實現這些設計目標?

  • 使用命令模式將所有對外部服務(或依賴關係)的呼叫包裝在HystrixCommand或HystrixObservableCommand物件中,並將該物件放在單獨的執行緒中執行;
  • 每個依賴都維護著一個執行緒池(或訊號量),執行緒池被耗盡則拒絕請求(而不是讓請求排隊)。
  • 記錄請求成功,失敗,超時和執行緒拒絕。
  • 服務錯誤百分比超過了閾值,熔斷器開關自動開啟,一段時間內停止對該服務的所有請求。
  • 請求失敗,被拒絕,超時或熔斷時執行降級邏輯。
  • 近實時地監控指標和配置的修改。

五、應用實戰

專案還是用以前的專案,之前在spring-cloud-user寫了一個UserController,在裡面呼叫了spring-cloud-service服務,下面把除了spring-cloud-service外的其它服務都開啟,然後訪問介面會發現報錯,看控制檯,控制檯報的是連線異常,這就是一個典型的通訊失敗的案例,在生產過程中如果訪問報一個這個頁面總是不那麼友好的,那麼怎麼解決這個通訊失敗呢。

 

 

 

 

 為了解決這個問題就引入了hystrix,在服務呼叫端加入Hystrix包,因為我後面每個應用都會加入spring-cloud-api這個工程,為了減少後面應用重複導包,我將此包放入spring-cloud-api工程,並且要在呼叫端加入@EnableCircuitBreaker註解

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

然後就可以對服務進行降級和熔斷機制了,在UserController類方法中加入@HystrixCommand(fallbackMethod = "fallback")

 

 

 然後再訪問瀏覽器,發現沒啥用,

 

 

 

 

 

 

這正好引出今天問題,怎麼觸發降級,剛剛配置的方法其實是回退,降級有三種方案:

  5.1、熔斷觸發降級

       熔斷的配置資訊可以在HystrixCommandProperties類中找到,這裡我只寫3個

 

 

 然後再次發起訪問,發現發生了熔斷

 

 

 這裡有個問題,我這裡不演示了,那就是熔斷開啟之後,後續的正常請求也無法傳送過去;說完了這個下面就看下,熔斷是如何觸發的的,又是怎麼恢復的;

1.如何觸發熔斷?"判斷閾值"

     10s鍾之內,發起了20次請求,失敗率超過50%。 熔斷的恢復時間(熔斷5s)也就是說熔斷觸發了後,後續請求在5S內都不會發生到服務端 ,這就是熔斷的時間視窗說明.

2.熔斷會有一個自動恢復。

     自支恢復的概念是,5S後請求會自動試著傳送到服務端,如果發現傳送通訊正常了,熔斷就會成為關閉狀態

5.2、請求超時觸發降級

        在繼續寫時要說明一個情況那就是熔斷後超時是兩個概念,希望不要搞混了,超時是請求傳送中只是時間超了閾值

 

 

 

 

 

 5.3、資源隔離觸發降級

    隔離分為平臺隔離、部署隔離、業務隔離、 服務隔離、資源隔離;比喻說專案中的一個case,有一塊東西,是要用多執行緒做一些事情,小夥伴做專案的時候,沒有太留神,資源隔離,那塊程式碼,在遇到一些故障的情況下,每個執行緒在跑的時候,因為那個bug,直接就死迴圈了,導致那塊東西啟動了大量的執行緒,每個執行緒都死迴圈最終導致系統資源耗盡,崩潰,不工作,不可用,廢掉了;在系統中值得我們隔離的資源無非就幾種:CPU、記憶體、執行緒

訊號量隔離:

/**
  * 訊號量隔離實現
  * 不會使用Hystrix管理的執行緒池處理請求。使用容器(Tomcat)的執行緒處理請求邏輯。
  * 不涉及執行緒切換,資源排程,上下文的轉換等,相對效率高。
  * 訊號量隔離也會啟動熔斷機制。如果請求併發數超標,則觸發熔斷,返回fallback資料。
  * commandProperties - 命令配置,HystrixPropertiesManager中的常量或字串來配置。
  *   execution.isolation.strategy - 隔離的種類,可選值只有THREAD(執行緒池隔離)和
SEMAPHORE(訊號量隔離)。
  *   預設是THREAD執行緒池隔離。
  *   設定訊號量隔離後,執行緒池相關配置失效。
  * execution.isolation.semaphore.maxConcurrentRequests - 訊號量最大併發數。預設
值是10。常見配置500~1000。
  *   如果併發請求超過配置,其他請求進入fallback邏輯。
  */
@HystrixCommand(fallbackMethod="semaphoreQuarantineFallback",
        commandProperties={
          @HystrixProperty(
          
 name=HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY,
            value="SEMAPHORE"), // 訊號量隔離
          @HystrixProperty(
          
 name=HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQU
ESTS,
            value="100") // 訊號量最大併發數

執行緒池隔離

@HystrixCommand(groupKey="spring-cloud-service",
      commandKey = "orders",
      threadPoolKey="spring-cloud-service",
      threadPoolProperties = {
          @HystrixProperty(name = "coreSize", value = "30"),//執行緒池大小
          @HystrixProperty(name = "maxQueueSize", value = "100"),//最大佇列長度

          @HystrixProperty(name =  "keepAliveTimeMinutes", value ="2"),//執行緒存活時間

          @HystrixProperty(name = "queueSizeRejectionThreshold", value= "15")//拒絕請求

     },
      fallbackMethod = "fallback")

 

六、OpenFeign的降級策略

前面講了hystrilx的降級方法,也在之前的篇幅中講了OpenFeign的應用,下面就以hystrix為基礎來講下在OpenFeign中是怎麼做到降級的進行對比一下,記得用OpenFeign要開啟降級和之前篇幅一樣要匯入包還有在啟動類上加上

@EnableFeignClients(basePackages = "com.ghy.*")註解,另外還要在呼叫者的配置檔案中加入下面的開啟配置
#開啟feign的支援,觸發降級的策略
feign:
  hystrix:
    enabled: true

這些搞定後,那就寫降級策略了

 

 

 訪問瀏覽器

 

 

 如果想在OpenFeign和hystrix一樣配置很多資訊的話是沒辦法用註解配置的,只能在配置檔案中配置,下面配置下超時的時間配置,在呼叫端的配置檔案中配置

#開啟feign的支援,觸發降級的策略
feign:
  hystrix:
    enabled: true
hystrix:
  command:
    default:  #全域性配置, feignclient#method(param)
      execution:
        timeout:
          enable: true  #超時的開啟
        isolation:
          thread:
            timeoutInMilliseconds: 3000  #設定超時時間

#設定ribbon的超時時間,而且ribbon的超時時間一定要大於hystrix,這樣才能讓hystrix生效
ribbon:
  ReadTimeout: 10000
  ConnectTimeout: 10000

 

 

 

 

 

 

 下面看下執行緒池隔離的配置

 

 

 

 

 

 然後建立一個spring-cloud-hystrix專案進行監控,在spring-cloud-hystrix匯入以下包,然後spring-cloud-hystrix的啟動類上加上@EnableHystrixDashboard註解

      <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>

配置檔案如下

server:
  port: 9095

eureka:
  instance:
    hostname: localhost
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/  #指向服務註冊中心的地址

訪問瀏覽器登入到了登入皮膚,被監測的服務一定要有下面的包

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

並且被監控的物件要配置如下配置以不斷獲取監控資訊

management:
  endpoints:
    web:
      exposure:
        include: refresh,hystrix.stream

 

 

 

 因為spring-cloud-user服務的埠號是8090,在瀏覽器上訪問 http://localhost:8090/actuator/hystrix.stream可以發現在不停的Ping我們的服務,其實這皮膚的作用就是將ping的結果收集然後在皮膚上展示

 

 

 

在皮膚上輸入要監控的服務資訊,如果要監控多個這皮膚也能做到,要做一個聚合操作

 

 

 

 

 

 

下面有三行資料,左邊第一行表示成功數,左邊第二行表示熔斷數量,左邊最後一行表示失敗數量

如果有興趣的朋友可以下個Apache JMeter壓測工具壓測玩下,我電腦換系統了工具丟了就懶得搞了,這工具也挺簡單的

 

 

 git網址:https://github.com/ljx958720/Spring-Cloud-Hystrix.git

 

相關文章