SpringCloud實戰之路 | 應用篇(三)服務熔斷器Hystrix工作流程及高級應用

SpringCloud實戰之路 | 應用篇(三)服務熔斷器Hystrix工作流程及高級應用

Hystrix介紹

Hystrix,宣言“defend your app”是由Netflix開源的一個延遲和容錯庫,用於隔離訪問遠程系統、服務或者第三方庫,防止級聯失敗,從而提升系統的可用性與容錯性。Hystrix主要通過以下幾點實現延遲和容錯。

  • 包裹請求:使用HystrixCommand包裹對依賴的調⽤邏輯。 自動投遞微服務方法(@HystrixCommand 添加Hystrix控制)
  • 跳閘機制:當某服務的錯誤率超過一定的閾值時,Hystrix可以跳閘,停止請求該服務一段時間。
  • 資源隔離:Hystrix爲每個依賴都維護了一個小型的線程池(艙壁模式)(或者信號量)。如果該線程池已滿, - 發往該依賴的請求就被立即拒絕,而不是排隊等待,從而加速失敗判定。
  • 監控:Hystrix可以近乎實時地監控運行指標和配置的變化,例如成功、失敗、超時、以及被拒絕的請求等。
  • 回退機制:當請求失敗、超時、被拒絕,或當斷路器打開時,執行回退邏輯。回退邏輯由開發人員自行提供,例如返回一個缺省值。
  • 自我修復:斷路器打開一段時間後,會自動進入“半開”狀態

在這裏插入圖片描述

具體實現

引入maven依賴座標

<!--熔斷器Hystrix-->
<dependency>
 <groupId>org.springframework.cloud</groupId>
 <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

啓動類添加熔斷器開啓註解@EnableCircuitBreaker

@SpringBootApplication
@EnableDiscoveryClient // 開啓服務發現
@EnableCircuitBreaker // 開啓熔斷
public class Application {
	 public static void main(String[] args) {
	 	SpringApplication.run(Application .class, args);
	 }
	 /**
	 * 注⼊RestTemplate
	 * @return
	 */
	 @Bean
	 // Ribbon負載均衡
	 @LoadBalanced
	 public RestTemplate getRestTemplate() {
	 	return new RestTemplate();
	 }
}

定義服務降級處理方法,並在業務方法上使用@HystrixCommand的fallbackMethod屬性關聯到
服務降級處理方法

@RestController
@RequestMapping("/test")
public class TestController {


    @Autowired
    private RestTemplate restTemplate;

	@GetMapping("/test/{id}")
    @HystrixCommand(
            // 線程池標識,要保持唯一,不唯一的話就共用了
            threadPoolKey = "findResumeOpenStateTimeoutFallback",
            // 線程池細節屬性配置
            threadPoolProperties = {
                    @HystrixProperty(name="coreSize",value = "2"), // 線程數
                    @HystrixProperty(name="maxQueueSize",value="20") // 等待隊列長度
            },
            // commandProperties熔斷的一些細節屬性配置
            commandProperties = {
                    // 每一個屬性都是一個HystrixProperty                   @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000")
                    // hystrix高級配置,定製工作過程細節
                    ,
                    // 統計時間窗口定義
                    @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value = "8000"),
                    // 統計時間窗口內的最小請求數
                    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "2"),
                    // 統計時間窗口內的錯誤數量百分比閾值
                    @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50"),
                    // 自我修復時的活動窗口長度
                    @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "3000")



            },
            fallbackMethod = "myFallBack"  // 回退方法
    )
    public Integer test(@PathVariable Long id) {
        // 使用ribbon不需要我們自己獲取服務實例然後選擇一個那麼去訪問了(自己的負載均衡)
        String url = "http://server/test/" + id;  // 指定服務名
        Integer forObject = restTemplate.getForObject(url, Integer.class);
        return forObject;
    }


    /*
        定義回退方法,返回預設默認值
        注意:該方法形參和返回值與原始方法保持一致
     */
    public Integer myFallBack(Long id) {
        return -123333; // 兜底數據
    }
}

注意
降級(兜底)方法必須和被降級方法相同的方法簽名(相同參數列表、相同返回值)

測試
當請求超時時候返回直接返回降級方法結果

結果:
-123333

Hystrix工作流程

 Hystrix工作流程

  1. 在調用出現問題時,會開啓一個時間窗(默認爲10s)
  2. 在這個時間窗內,統計請求次數是否達到了最小的請求數
    如果未達到最小的請求數,則重置統計信息回到第一步(因爲在請求數過少的情況下,有可能是偶爾出現的調用問題,後面就不會採取跳閘,或者切斷的措施,要達到一定數量的統計纔有意義)
    如果達到最小的請求數,則統計請求失敗的數量佔所有請求數量的百分比是否達到閾值,
    如果未達到閾值則重置統計信息回到第一步(原因同最小請求數)
    如果達到閾值,跳閘(不在請求對應服務)
  3. 如果跳閘,會打開一個新的活動窗口(默認5s),會每隔5s,Hystrix放行一個請求,到達問題服務,看是否調用成功,如果成功,則認爲該服務恢復正常,重置斷路器回到第1步,如果失敗,回到第3步。

其中的參數通過配置可以定製修改

  • execution.isolation.thread.timeoutInMilliseconds: 降級處理超時時間
  • metrics.rollingStats.timeInMilliseconds : 統計時間窗口定義
  • circuitBreaker.requestVolumeThreshold : 統計時間窗口內的最小請求數
  • circuitBreaker.errorThresholdPercentage: 統計時間窗口內的錯誤數量百分比閾值
  • circuitBreaker.sleepWindowInMilliseconds: 自我修復時的活動窗口長度
	@GetMapping("/test/{id}")
    @HystrixCommand(
            // commandProperties熔斷的一些細節屬性配置
            commandProperties = {
                    // 每一個屬性都是一個HystrixProperty
                    //降級處理超時時間
                    @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000"),

                    // hystrix高級配置,定製工作過程細節
                    
                    // 統計時間窗口定義
                    @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value = "8000"),
                    // 統計時間窗口內的最小請求數
                    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "2"),
                    // 統計時間窗口內的錯誤數量百分比閾值
                    @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50"),
                    // 自我修復時的活動窗口長度
                    @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "3000")

            },
            fallbackMethod = "myFallBack"  // 回退方法
    )
    public Integer test(@PathVariable Long id) {
        // 使用ribbon不需要我們自己獲取服務實例然後選擇一個那麼去訪問了(自己的負載均衡)
        String url = "http://server/test/" + id;  // 指定服務名
        Integer forObject = restTemplate.getForObject(url, Integer.class);
        return forObject;
    }
    
	/*
     *  定義回退方法,返回預設默認值
     *  注意:該方法形參和返回值與原始方法保持一致
     */
    public Integer myFallBack(Long userId) {
        return -1; // 兜底數據
    }

Hystrix艙壁模式(線程池隔離策略)

默認情況下,Hystrix有一個線程池(10個),所有加了@HystrixCommand註解的方法共用這一個線程池,如果這些方法接受的請求超過了10個,其他請求就會等待或者拒絕連接。
在這裏插入圖片描述
如果不進行設置,所有熔斷方法將會公用一個Hystrix線程池(10個線程),如果方法1有把10個線程都佔用了,方法2請求處理時不會去訪問B服務,因爲無線程可用。

爲了處理由於請求過多而導致服務無法訪問,hystrix不是採用增加線程數,而是可以爲每一個方法單獨開啓一個線程池,這種模式叫做艙壁模式,也是線程隔離的⼿段。
在這裏插入圖片描述
配置方式:

	@HystrixCommand(
            // 線程池標識,要保持唯一,不唯一的話就共用了
            threadPoolKey = "test",
            // 線程池細節屬性配置
            threadPoolProperties = {
                    @HystrixProperty(name="coreSize",value = "1"), // 線程數
                    @HystrixProperty(name="maxQueueSize",value="20") // 等待隊列長度
            },
            // commandProperties熔斷的一些細節屬性配置
            commandProperties = {
                    // 每一個屬性都是一個HystrixProperty
                    //降級處理超時時間
                    @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000")
            }
    )
    @GetMapping("/test/{id}")
    public Integer test(@PathVariable Long id) {
        // 使用ribbon不需要我們自己獲取服務實例然後選擇一個那麼去訪問了(自己的負載均衡)
        String url = "http://server/test/" + id;  // 指定服務名
        Integer forObject = restTemplate.getForObject(url, Integer.class);
        return forObject;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章