本系列博文為學習資料,是根據老師講義,加上自己了解描述整理而成。如有不當之處希望不吝指正,持續更新改正。
服務雪崩
雪崩是系統中的蝴蝶效應導緻其發生的原因多種多樣,有不合理的容量設計,或者是高并發 下某一個方法響應變慢,亦或是某台機器的資源耗盡。從源頭上我們無法完全杜絕雪崩源頭 的發生,但是雪崩的根本原因來源于服務之間的強依賴,是以我們可以提前評估。當整個微 服務系統中,有一個節點出現異常情況,就有可能在高并發的情況下出現雪崩,導緻調用它 的上遊系統出現響應延遲,響應延遲就會導緻 tomcat 連接配接本耗盡,導緻該服務節點不能正 常的接收到正常的情況,這就是服務雪崩行為。
這裡直接附上老師的例子:
服務隔離
如果整個系統雪崩是由于一個接口導緻的,由于這一個接口響應不及時導緻問題,那麼我們 就有必要對這個接口進行隔離,就是隻允許這個接口最多能接受多少的并發,做了這樣的限 制後,該接口的主機就會空餘線程出來接收其他的情況,不會被哪個壞了的接口占用滿。 Hystrix 就是一個不錯的服務隔離架構。
Hystrix 的導入
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
啟動類開啟 hystrix 功能
import com.xiangxue.jack.service.feign.StudentService;
import com.xiangxue.jack.service.feign.TeacherServiceFeign;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication(scanBasePackages = {"com.xiangxue.jack"})
//注冊到eureka
@EnableEurekaClient
//開啟斷路器功能
@EnableCircuitBreaker
//開啟feign支援,clients指定哪個類開啟feign
@EnableFeignClients(clients = {StudentService.class,TeacherServiceFeign.class})
//開啟重試功能
@EnableRetry
public class MicroWebApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate() {
// HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
// factory.setConnectionRequestTimeout(2000);
// factory.setReadTimeout(4000);
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(MicroWebApplication.class,args);
}
}
代碼使用:
@HystrixCommand
@Override
public String queryTicket() {
return "queryTicket1";
}
Hystrix 服務隔離政策
1、線程池隔離
THREAD 線程池隔離政策 獨立線程接收請求 預設的
預設采用的就是線程池隔離
代碼配置
/**
* Command屬性
* execution.isolation.strategy 執行的隔離政策
* THREAD 線程池隔離政策 獨立線程接收請求
* SEMAPHORE 信号量隔離政策 在調用線程上執行
* <p>
* execution.isolation.thread.timeoutInMilliseconds 設定HystrixCommand執行的逾時時間,機關毫秒
* execution.timeout.enabled 是否啟動逾時時間,true,false
* execution.isolation.semaphore.maxConcurrentRequests 隔離政策為信号量的時候,該屬性來配置信号量的大小,最大并發達到信号量時,後續請求被拒絕
* <p>
* circuitBreaker.enabled 是否開啟斷路器功能
* circuitBreaker.requestVolumeThreshold 該屬性設定在滾動時間視窗中,斷路器的最小請求數。預設20,如果在視窗時間内請求次數19,即使19個全部失敗,斷路器也不會打開
* circuitBreaker.sleepWindowInMilliseconds 改屬性用來設定當斷路器打開之後的休眠時間,休眠時間結束後斷路器為半開狀态,斷路器能接受請求,如果請求失敗又重新回到打開狀态,如果請求成功又回到關閉狀态
* circuitBreaker.errorThresholdPercentage 該屬性設定斷路器打開的錯誤百分比。在滾動時間内,在請求數量超過circuitBreaker.requestVolumeThreshold,如果錯誤請求數的百分比超過這個比例,斷路器就為打開狀态
* circuitBreaker.forceOpen true表示強制打開斷路器,拒絕所有請求
* circuitBreaker.forceClosed true表示強制進入關閉狀态,接收所有請求
* <p>
* metrics.rollingStats.timeInMilliseconds 設定滾動時間窗的長度,機關毫秒。這個時間視窗就是斷路器收集資訊的持續時間。斷路器在收集名額資訊的時會根據這個時間視窗把這個視窗拆分成多個桶,每個桶代表一段時間的名額,預設10000
* metrics.rollingStats.numBuckets 滾動時間窗統計名額資訊劃分的桶的數量,但是滾動時間必須能夠整除這個桶的個數,要不然抛異常
* <p>
* requestCache.enabled 是否開啟請求緩存,預設為true
* requestLog.enabled 是否列印日志到HystrixRequestLog中,預設true
*
* @HystrixCollapser 請求合并
* maxRequestsInBatch 設定一次請求合并批進行中允許的最大請求數
* timerDelayInMilliseconds 設定批處理過程中每個指令延遲時間
* requestCache.enabled 批處理過程中是否開啟請求緩存,預設true
* <p>
* threadPoolProperties
* threadPoolProperties 屬性
* coreSize 執行指令線程池的最大線程數,也就是指令執行的最大并發數,預設10
*/
@HystrixCommand(fallbackMethod = "queryContentsFallback",
commandKey = "queryContents",
groupKey = "querygroup-one",
commandProperties = {
@HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests",value = "100"),
@HystrixProperty(name = "execution.isolation.strategy", value = "SEMAPHORE"),
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000000000")
},
threadPoolKey = "queryContentshystrixJackpool", threadPoolProperties = {
// @HystrixProperty(name = "coreSize", value = "100")
})
預設線程池中有 10 個線程,可以配置線程池中線程大小
線程池隔離政策,hystrix 是會單獨建立線程的,單元測試如下:
可以看到,使用者線程和業務類中的線程是不一樣的
2、信号量隔離
信号量隔離是采用一個全局變量來控制并發量,一個請求過來全局變量加 1,單加到跟配置 中的大小相等是就不再接受使用者請求了。
代碼配置
execution.isolation.semaphore.maxConcurrentRequests 這參數是用來控制信号量隔離級别的并發大小的。
單元測試
可以看到,單元測試中的線程和業務類中的線程是一樣的,沒有單獨開啟線程。
Hystrix 服務降級
服務降級是對服務調用過程的出現的異常的友好封裝,當出現異常時,我們不希 望直接把異常原樣傳回,是以當出現異常時我們需要對異常資訊進行包裝,抛一 個友好的資訊給前端。
Hystrix 降級的使用比較簡單
代碼示例
/**
* Command屬性
* execution.isolation.strategy 執行的隔離政策
* THREAD 線程池隔離政策 獨立線程接收請求
* SEMAPHORE 信号量隔離政策 在調用線程上執行
* <p>
* execution.isolation.thread.timeoutInMilliseconds 設定HystrixCommand執行的逾時時間,機關毫秒
* execution.timeout.enabled 是否啟動逾時時間,true,false
* execution.isolation.semaphore.maxConcurrentRequests 隔離政策為信号量的時候,該屬性來配置信号量的大小,最大并發達到信号量時,後續請求被拒絕
* <p>
* circuitBreaker.enabled 是否開啟斷路器功能
* circuitBreaker.requestVolumeThreshold 該屬性設定在滾動時間視窗中,斷路器的最小請求數。預設20,如果在視窗時間内請求次數19,即使19個全部失敗,斷路器也不會打開
* circuitBreaker.sleepWindowInMilliseconds 改屬性用來設定當斷路器打開之後的休眠時間,休眠時間結束後斷路器為半開狀态,斷路器能接受請求,如果請求失敗又重新回到打開狀态,如果請求成功又回到關閉狀态
* circuitBreaker.errorThresholdPercentage 該屬性設定斷路器打開的錯誤百分比。在滾動時間内,在請求數量超過circuitBreaker.requestVolumeThreshold,如果錯誤請求數的百分比超過這個比例,斷路器就為打開狀态
* circuitBreaker.forceOpen true表示強制打開斷路器,拒絕所有請求
* circuitBreaker.forceClosed true表示強制進入關閉狀态,接收所有請求
* <p>
* metrics.rollingStats.timeInMilliseconds 設定滾動時間窗的長度,機關毫秒。這個時間視窗就是斷路器收集資訊的持續時間。斷路器在收集名額資訊的時會根據這個時間視窗把這個視窗拆分成多個桶,每個桶代表一段時間的名額,預設10000
* metrics.rollingStats.numBuckets 滾動時間窗統計名額資訊劃分的桶的數量,但是滾動時間必須能夠整除這個桶的個數,要不然抛異常
* <p>
* requestCache.enabled 是否開啟請求緩存,預設為true
* requestLog.enabled 是否列印日志到HystrixRequestLog中,預設true
*
* @HystrixCollapser 請求合并
* maxRequestsInBatch 設定一次請求合并批進行中允許的最大請求數
* timerDelayInMilliseconds 設定批處理過程中每個指令延遲時間
* requestCache.enabled 批處理過程中是否開啟請求緩存,預設true
* <p>
* threadPoolProperties
* threadPoolProperties 屬性
* coreSize 執行指令線程池的最大線程數,也就是指令執行的最大并發數,預設10
*/
@HystrixCommand(fallbackMethod = "queryContentsFallback",
commandKey = "queryContents",
groupKey = "querygroup-one",
commandProperties = {
@HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests",value = "100"),
@HystrixProperty(name = "execution.isolation.strategy", value = "SEMAPHORE"),
// @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD"),
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000000000")
},
threadPoolKey = "queryContentshystrixJackpool", threadPoolProperties = {
// @HystrixProperty(name = "coreSize", value = "100")
})
指定降級方法
定義降級方法,降級方法的傳回值和業務方法的方法值要一樣
Hystrix 資料監控
Hystrix 進行服務熔斷時會對調用結果進行統計,比如逾時數、bad 請求數、降 級數、異常數等等都會有統計,那麼統計的資料就需要有一個界面來展示, hystrix-dashboard 就是這麼一個展示 hystrix 統計結果的服務。
Dashboard 工程搭建
pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
啟動類
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
/*
* 監控界面:http://localhost:9990/hystrix
* 需要監控的端點(使用了hystrix元件的端點):http://localhost:8083/actuator/hystrix.stream
*
* */
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardApplication.class,args);
// new SpringApplicationBuilder(HystrixDashboardApplication.class).web(true).run(args);
}
}
Dashboadr 界面
http://localhost:9990/hystrix
然後在界面中輸入需要監控的端點 url:
http://localhost:8083/actuator/hystrix.stream
Hystrix熔斷
熔斷就像家裡的保險絲一樣,家裡的保險絲一旦斷了,家裡就沒點了,家裡用電器功率高了就會導緻保險絲端掉。在我們springcloud領域也可以這樣了解,如果并發高了就可能觸發hystrix的熔斷。
熔斷發生的三個必要條件:
-
1、有一個統計的時間周期,滾動視窗
相應的配置屬性
metrics.rollingStats.timeInMilliseconds
預設10000毫秒
-
2、請求次數必須達到一定數量
相應的配置屬性
circuitBreaker.requestVolumeThreshold
預設20次
-
3、失敗率達到預設失敗率
相應的配置屬性
circuitBreaker.errorThresholdPercentage
預設50%
上述3個條件缺一不可,必須全部滿足才能開啟hystrix的熔斷功能。
當我們的對一個線程池大小是100的方法壓測時看看hystrix的熔斷效果:
Jmeter壓測:
Hystrix dashboard界面
可以看到失敗率超過50%時,circuit的狀态是open的。
熔斷器的三個狀态:
-
1、關閉狀态
關閉狀态時使用者請求是可以到達服務提供方的
-
2、開啟狀态
開啟狀态時使用者請求是不能到達服務提供方的,直接會走降級方法
-
3、半開狀态
當hystrix熔斷器開啟時,過一段時間後,熔斷器就會由開啟狀态變成半開狀态。
半開狀态的熔斷器是可以接受使用者請求并把請求傳遞給服務提供方的,這時候如果遠端調用傳回成功,那麼熔斷器就會有半開狀态變成關閉狀态,反之,如果調用失敗,熔斷器就會有半開狀态變成開啟狀态。
Hystrix功能建議在并發比較高的方法上使用,并不是所有方法都得使用的。
練習項目代碼:https://share.weiyun.com/5bigglx