【SpringCloud】Hystrix服務隔離(十二)


服務隔離介紹

  當大多數人在使用Tomcat時,多個HTTP服務會共享一個線程池,假設其中一個HTTP服務訪問的數據庫響應非常慢,這將造成服務響應時間延遲增加,大多數線程阻塞等待數據響應返回,導致整個Tomcat線程池都被該服務占用,甚至拖垮整個Tomcat。因此,如果我們能把不同HTTP服務隔離到不同的線程池,則某個HTTP服務的線程池滿了也不會對其他服務造成災難性故障。這就需要線程隔離或者信號量隔離來實現了。

  使用線程隔離或信號隔離的目的是為不同的服務分配一定的資源,當自己的資源用完,直接返回失敗而不是占用別人的資源。

  Hystrix實現服務隔離兩種方案

  Hystrix的資源隔離策略有兩種,分別為:線程池和信號量。

線程池方式

  優點:

  1、 使用線程池隔離可以完全隔離第三方應用,請求線程可以快速放回。

  2、 請求線程可以繼續接受新的請求,如果出現問題線程池隔離是獨立的不會影響其他應用。

  3、 當失敗的應用再次變得可用時,線程池將清理並可立即恢復,而不需要一個長時間的恢復。

  4、 獨立的線程池提高了並發性

  缺點:

  線程池隔離的主要缺點是它們增加計算開銷(CPU)。每個命令的執行涉及到排隊、調度和上 下文切換都是在一個單獨的線程上運行的。

  線程池方式案例

  1、使用上一章項目工程,在服務端項目的業務類Service中編寫如下方法:

 1 // 服務限流
 2 @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_Thread",
 3         // 屬性設置參考:HystrixCommandProperties
 4         commandProperties = {
 5                 // 隔離策略,有THREAD和SEMAPHORE
 6                 @HystrixProperty(name="execution.isolation.strategy", value="THREAD")
 7         },
 8         threadPoolProperties = {
 9                 // 線程池核心線程數
10                 @HystrixProperty(name = "coreSize", value = "3"),
11                 // 隊列最大長度
12                 @HystrixProperty(name = "maxQueueSize", value = "5"),
13                 // 排隊線程數量閾值,默認為5,達到時拒絕,如果配置了該選項,隊列的大小是該隊列
14                 @HystrixProperty(name = "queueSizeRejectionThreshold", value = "7")
15         })
16 public String paymentCircuitBreakerThread(@PathVariable("id") Integer id){
17     int second = 500;
18     try {
19         // 休眠500毫秒
20         TimeUnit.MILLISECONDS.sleep(second);
21     } catch (InterruptedException e) {
22 //            e.printStackTrace();
23     }
24     // 異常
25 //        int n = 10/0;
26     String result = "線程池:" + Thread.currentThread().getName()
27             + ",paymentCircuitBreakerThreadPool,ID == " + id
28             + ",耗時" + second + "毫秒";
29     return result;
30 }
31 
32 public String paymentCircuitBreaker_Thread(@PathVariable("id") Integer id){
33     return " paymentCircuitBreaker_Thread 服務限流,ID == " + id;
34 }

  2、在controller中調用該方法

1 // 線程
2 @GetMapping(value = "/payment/hystrix/thread/{id}")
3 public String paymentCircuitBreakerThreadPool(@PathVariable("id") Integer id) {
4     String result = paymentService.paymentCircuitBreakerThread(id);
5     log.info("result===" + result);
6     return result;
7 }

  3、重啟項目,使用JMeter進行並發測試,測試url地址:http://localhost:8008/payment/hystrix/thread/1

    測試發現,有一部分請求調用了fallback方法,一部分正常響應

    

信號量方式  

  使用一個原子計數器(或信號量)來記錄當前有多少個線程在運行,當請求進來時先判斷計數 器的數值,若超過設置的最大線程個數則拒絕該請求,若不超過則通行,這時候計數器+1,請求返 回成功后計數器-1。

  與線程池隔離最大不同在於執行依賴代碼的線程依然是請求線程

  提示:信號量的大小可以動態調整, 線程池大小不可以

  信號量方式案例

  1、使用上一章項目工程,在服務端項目的業務類Service中編寫如下方法:

 1 // 服務限流
 2 @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_Semaphore",
 3         // 屬性設置參考:HystrixCommandProperties
 4         commandProperties = {
 5                 // 隔離策略,有THREAD和SEMAPHORE
 6                 // THREAD - 它在單獨的線程上執行,並發請求受線程池中的線程數量的限制(默認)
 7                 // SEMAPHORE - 它在調用線程上執行,並發請求受到信號量計數的限制
 8                 @HystrixProperty(name="execution.isolation.strategy", value="SEMAPHORE"),
 9                 // 設置在使用時允許到HystrixCommand.run()方法的最大請求數。默認值:10 ,SEMAPHORE模式有效
10                 @HystrixProperty(name="execution.isolation.semaphore.maxConcurrentRequests", value="1")
11 
12         })
13 public String paymentCircuitBreakerSemaphore(@PathVariable("id") Integer id){
14     int second = 500;
15     try {
16         // 休眠500毫秒
17         TimeUnit.MILLISECONDS.sleep(second);
18     } catch (InterruptedException e) {
19 //            e.printStackTrace();
20     }
21     // 異常
22 //        int n = 10/0;
23     String result = "線程池:" + Thread.currentThread().getName()
24             + ",paymentCircuitBreaker_Semaphore,ID == " + id
25             + ",耗時" + second + "毫秒";
26     return result;
27 }
28 
29 public String paymentCircuitBreaker_Semaphore(@PathVariable("id") Integer id){
30     return " paymentCircuitBreaker_Semaphore 服務限流,ID == " + id;
31 }

  2、在controller中調用該方法

1 // 信號量
2 @GetMapping(value = "/payment/hystrix/semaphore/{id}")
3 public String paymentCircuitBreakerLimit(@PathVariable("id") Integer id) {
4     String result = paymentService.paymentCircuitBreakerSemaphore(id);
5     log.info("result===" + result);
6     return result;
7 }

  3、重啟項目,使用JMeter進行並發測試,測試url地址:http://localhost:8008/payment/hystrix/semaphore/1

    測試發現,有一部分請求調用了fallback方法,一部分正常響應

    

 


免責聲明!

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



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