SpringCloud(十)服務雪崩與熔斷Hystrix


 

 

 

 

@author QYX 由於學習任務繁多,近期暫停了幾天搬運,兩天后恢復

引入服務熔斷Hystrix

 

 

 

簡單是來說,在分布式系統中,假如有一個請求需要調用A服務,但A服務出現了問題,則這個請求就會阻塞,那么只要調用服務A的請求都會阻塞,當阻塞的請求越來越多,占用的計算機資源就越來越多。進一步來說,就是一個服務出現問題,可能導致所有的請求都不可用,從而導致整個分布式系統都不可用,這就是“雪崩效應”。

雪崩效應常見場景

  • 硬件故障:如服務器宕機,機房斷電,光纖被挖斷等。

  • 流量激增:如異常流量,重試加大流量等。

  • 緩存穿透:一般發生在應用重啟,所有緩存失效時,以及短時間內大量緩存失效時。大量的緩存不命中,使請求直擊后端服務,造成服務提供者超負荷運行,引起服務不可用。

  • 程序BUG:如程序邏輯導致內存泄漏,JVM長時間FullGC等。

  • 同步等待:服務間采用同步調用模式,同步等待造成的資源耗盡。

雪崩效應應對策略

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

  • 硬件故障:多機房容災、異地多活等。

  • 流量激增:服務自動擴容、流量控制(限流、關閉重試)等。

  • 緩存穿透:緩存預加載、緩存異步加載等。

  • 程序BUG:修改程序bug、及時釋放資源等。

  • 同步等待:資源隔離、MQ解耦、不可用服務調用快速失敗等。資源隔離通常指不同服務調用采用不同的線程池;不可用服務調用快速失敗一般通過熔斷器模式結合超時機制實現。

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

服務隔離

服務降級

Hystrix:

Hystrix [hɪst'rɪks],中文含義是豪豬,因其背上長滿棘刺,從而擁有了自我保護的能力。本文所說的Hystrix是Netflix開源的一款容錯框架,同樣具有自我保護能力。為了實現容錯和自我保護,下面我們看看Hystrix如何設計和實現的。

Hystrix設計目標:

  • 對來自依賴的延遲和故障進行防護和控制——這些依賴通常都是通過網絡訪問的

  • 阻止故障的連鎖反應

  • 快速失敗並迅速恢復

  • 回退並優雅降級

  • 提供近實時的監控與告警

Hystrix遵循的設計原則:

  • 防止任何單獨的依賴耗盡資源(線程)

  • 過載立即切斷並快速失敗,防止排隊

  • 盡可能提供回退以保護用戶免受故障

  • 使用隔離技術(例如隔板,泳道和斷路器模式)來限制任何一個依賴的影響

  • 通過近實時的指標,監控和告警,確保故障被及時發現

  • 通過動態修改配置屬性,確保故障及時恢復

  • 防止整個依賴客戶端執行失敗,而不僅僅是網絡通信

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

  • 使用命令模式將所有對外部服務(或依賴關系)的調用包裝在HystrixCommand或HystrixObservableCommand對象中,並將該對象放在單獨的線程中執行;

  • 每個依賴都維護着一個線程池(或信號量),線程池被耗盡則拒絕請求(而不是讓請求排隊)。

  • 記錄請求成功,失敗,超時和線程拒絕。

  • 服務錯誤百分比超過了閾值,熔斷器開關自動打開,一段時間內停止對該服務的所有請求。

  • 請求失敗,被拒絕,超時或熔斷時執行降級邏輯。

  • 近實時地監控指標和配置的修改。

Hystrix組件

 

 

 

對RestTemplate的支持

引入hystrix的依賴

order_service

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

 

 

在啟動類中激活Hystrix

order_service

 package qqq;
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.domain.EntityScan;
 import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
 import org.springframework.cloud.client.loadbalancer.LoadBalanced;
 import org.springframework.context.annotation.Bean;
 import org.springframework.web.client.RestTemplate;
 
 @SpringBootApplication
 @EntityScan("com.qqq.entity")
 //@EnableFeignClients
 //激活hystrix
 @EnableCircuitBreaker
 public class OrderApplication {
     public static void main(String[] args) {
         SpringApplication.run(OrderApplication.class,args);
    }
     /**
      * eureka和consul都集成了Ribbon
      * 使用spring提供的RestTemplate發送http請求到商品服務
      * 1 將RestTemplate對象交給容器管理
      * 2 使用其方法完成操作
      */
     @LoadBalanced //Ribbon自帶的負載均衡的注解
     @Bean
     public RestTemplate restTemplate()
    {
         return new RestTemplate();
    }
 
 
 }
 

配置熔斷觸發的降級邏輯

在order_service的controller中配置

    /**
      * 降級方法
      * 和需要收到保護的方法的返回值一致
      * 接口參數一致
      */
     public Product orderFallBack(Long id)
    {
         Product product=new Product();
         product.setProductName("觸發降級方法");
         return product;
    }

在需要受到保護的接口上使用@HystrixCommand配置

     @HystrixCommand(fallbackMethod = "orderFallBack")
     @RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
     public Product findById(@PathVariable("id") Long id)
    {
         Product product=null;
         product=productFeginClient.findById(id);
         return product;
    }

注意事項:

在之前的案例中,請求在超過1秒后都會返回錯誤信息,這是因為Hystrix的默認超時時長為1,我們可以通過配置修改這個值:

 hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMillisconds: 3000 #默認的連接超時為1s,如果1s沒有返回數據,hystrix會自動觸發降級邏輯

配置統一的降級方法:

 package com.qqq.controller;
 
 import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
 import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
 import com.qqq.entity.Product;
 import com.qqq.fegin.ProductFeginClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.cloud.client.ServiceInstance;
 import org.springframework.cloud.client.discovery.DiscoveryClient;
 import org.springframework.cloud.client.loadbalancer.LoadBalanced;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
 import org.springframework.web.client.RestTemplate;
 
 import java.util.List;
 
 @RestController
 @RequestMapping("/order")
 /**
  * 指定公共的屬性
  * 如果過在@DefaultProperties指定了公共的降級方法
  * 在@HystrixCommand不需要單獨指定了
  *
  */
 @DefaultProperties(defaultFallback = "defaultFallBack")
 public class OrderController {
    //注入RestTemplate對象
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private ProductFeginClient productFeginClient;
    /**
      * 使用注解配置熔斷保護
      * fallbackmethod:配置熔斷之后的降級方法
      * @param id
      * @return
      */
    @HystrixCommand
    @RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
    public Product findById(@PathVariable("id") Long id)
    {
        Product product=null;
        product=productFeginClient.findById(id);
        return product;
    }
    /**
      * 降級方法
      * 和需要收到保護的方法的返回值一致
      * 接口參數一致
      */
    public Product orderFallBack(Long id)
    {
        Product product=new Product();
        product.setProductName("觸發降級方法");
        return product;
    }
    public Product defaultFallBack()
    {
        Product product=new Product();
        product.setProductName("觸發統一的降級方法");
        return product;
    }
 }
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM