本篇會(huì)介紹下Hystrix的使用憾股,會(huì)從最簡(jiǎn)單的入門(mén)實(shí)例開(kāi)始英遭,然后會(huì)講述下Hystrix的隔離和熔斷的原理和流程介衔,最后講解下Hystrix的各類參數(shù)來(lái)指導(dǎo)大家更快上手。
1. Hystrix實(shí)例
1)Pom增加依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>
2)Application添加注解
@SpringBootApplication
@EnableHystrixDashboard
@EnableCircuitBreaker
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
3)controller增加HystrixCommand注解
Hystrix支持兩種方式定義HystrixCommand脚翘,一種是將類繼承自HystrixCommand類,重寫(xiě)run方法绍哎,另一種是在方法頭上寫(xiě)注解的方式来农,使用注解的方式代碼會(huì)比較清晰,將Hystrix代碼和業(yè)務(wù)代碼隔離開(kāi)崇堰,具體屬性含義在接下來(lái)的章節(jié)會(huì)詳細(xì)介紹沃于。
@RestController
public class TestController {
@HystrixCommand(fallbackMethod = "error", commandProperties = {
@HystrixProperty(name="execution.isolation.strategy", value = "THREAD"),
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "4000"),
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "40")
}, threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "1"),
@HystrixProperty(name = "maxQueueSize", value = "10"),
@HystrixProperty(name = "keepAliveTimeMinutes", value = "1000"),
@HystrixProperty(name = "queueSizeRejectionThreshold", value = "8"),
@HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "12"),
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "1440")
})
@RequestMapping(value = "/hello", method = RequestMethod.GET, produces = {"application/json;charset=UTF-8"})
public String hello(){
return "hello hystrix!";
}
public String error() {
return "hello error!";
}
}
4)Hystrix Dashboard
Hystrix自帶了DashBoard,如果監(jiān)控單個(gè)實(shí)例海诲,可以很方便的通過(guò)Hystrix的dashboard進(jìn)行查看運(yùn)行情況繁莹。
當(dāng)應(yīng)用運(yùn)行起來(lái)以后可以通過(guò)輸入http://localhost:8081/hystrix,如果看到小熊頁(yè)面表示進(jìn)入dashboard頁(yè)面特幔。
在輸入欄中輸入:http://localhost:8081/hystrix.stream可以查看這個(gè)階段的實(shí)時(shí)運(yùn)行情況咨演。
可以看到界面上按照service和接口都分別展示出來(lái),如果有多個(gè)接口也會(huì)依次列開(kāi)請(qǐng)求監(jiān)控情況蚯斯。
實(shí)例源碼下載:https://github.com/feiweiwei/springcloud-sample
2. Hystrxi熔斷隔離流程
Hystrix隔離的核心思想就是按照接口進(jìn)行線程池隔離薄风,在沒(méi)有接觸Hystrix之前,我們也考慮過(guò)使用線程池做隔離拍嵌,來(lái)實(shí)現(xiàn)隔離的功能遭赂,但是當(dāng)時(shí)考慮到每個(gè)接口都開(kāi)一個(gè)線程池,可能線程上下文切換會(huì)消耗很多性能横辆,但是按照NetFlix的測(cè)試情況可以發(fā)現(xiàn)因?yàn)榫€程池導(dǎo)致的性能損耗很少撇他,下面就介紹下熔斷隔離的流程。
Hystrix流程說(shuō)明:
1:每次調(diào)用創(chuàng)建一個(gè)新的HystrixCommand,把依賴調(diào)用封裝在run()方法中.
2:執(zhí)行execute()/queue做同步或異步調(diào)用.
3:判斷熔斷器(circuit-breaker)是否打開(kāi),如果打開(kāi)跳到步驟8,進(jìn)行降級(jí)策略,如果關(guān)閉進(jìn)入步驟.
4:判斷線程池/隊(duì)列/信號(hào)量是否跑滿狈蚤,如果跑滿進(jìn)入降級(jí)步驟8,否則繼續(xù)后續(xù)步驟.
5:調(diào)用HystrixCommand的run方法.運(yùn)行依賴邏輯
5a:依賴邏輯調(diào)用超時(shí),進(jìn)入步驟8.
6:判斷邏輯是否調(diào)用成功
6a:返回成功調(diào)用結(jié)果
6b:調(diào)用出錯(cuò)困肩,進(jìn)入步驟8.
7:計(jì)算熔斷器狀態(tài),所有的運(yùn)行狀態(tài)(成功, 失敗, 拒絕,超時(shí))上報(bào)給熔斷器,用于統(tǒng)計(jì)從而判斷熔斷器狀態(tài).
8:getFallback()降級(jí)邏輯.
以下四種情況將觸發(fā)getFallback調(diào)用:
(1):run()方法拋出非HystrixBadRequestException異常脆侮。
(2):run()方法調(diào)用超時(shí)
(3):熔斷器開(kāi)啟攔截調(diào)用
(4):線程池/隊(duì)列/信號(hào)量是否跑滿
8a:沒(méi)有實(shí)現(xiàn)getFallback的Command將直接拋出異常
8b:fallback降級(jí)邏輯調(diào)用成功直接返回
8c:降級(jí)邏輯調(diào)用失敗拋出異常
9:返回執(zhí)行成功結(jié)果
3.Hystrxi參數(shù)詳解
最開(kāi)始例子可以發(fā)現(xiàn)Hystrix通過(guò)注解的方式使用起來(lái)是非常簡(jiǎn)單的僻弹,只要搞清楚里面的各種參數(shù)就能用的很6,我整理了一下各個(gè)參數(shù)的作用他嚷,大家可以看下蹋绽,熟悉下整個(gè)Hystrix的功能。下面這張圖表示了Hystrix的熔斷圖筋蓖,很好理解卸耘,圖片來(lái)自官網(wǎng)。
execution
execution.isolation.strategy
表示隔離策略粘咖,隔離策略有兩種蚣抗,一種為線程隔離一種為信號(hào)量隔離,線程隔離是按照并發(fā)請(qǐng)求進(jìn)行線程池?cái)?shù)量進(jìn)行隔離,請(qǐng)求線程全部按照線程池設(shè)置屬性進(jìn)行處理翰铡,官方也是推薦使用這種隔離策略钝域,默認(rèn)也是按照線程隔離進(jìn)行處理。信號(hào)隔離也可以用于限制并發(fā)訪問(wèn)锭魔,防止阻塞擴(kuò)散, 與線程隔離最大不同在于執(zhí)行依賴代碼的線程依然是請(qǐng)求線程(該線程需要通過(guò)信號(hào)申請(qǐng)),如果客戶端是可信的且可以快速返回(例如系統(tǒng)做了redis或者其他內(nèi)存緩存)例证,可以使用信號(hào)隔離替換線程隔離,降低開(kāi)銷.信號(hào)量的大小可以動(dòng)態(tài)調(diào)整, 線程池大小不可以動(dòng)態(tài)調(diào)整.
@HystrixCommand(fallbackMethod = "error", commandProperties = {
@HystrixProperty(name="execution.isolation.strategy", value = "THREAD")
})
execution.isolation.thread.timeoutInMilliseconds
這個(gè)就比較簡(jiǎn)單了,表示請(qǐng)求線程總超時(shí)時(shí)間迷捧,如果超過(guò)這個(gè)設(shè)置的時(shí)間hystrix就會(huì)調(diào)用fallback方法织咧。value的參數(shù)為毫秒,默認(rèn)值為1000ms漠秋。
@HystrixCommand(fallbackMethod = "error", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "4000")
})
execution.timeout.enabled
這個(gè)超時(shí)開(kāi)關(guān)表示笙蒙,當(dāng)超時(shí)后是否觸發(fā)fallback方法,默認(rèn)為true庆锦。
execution.isolation.semaphore.maxConcurrentRequests
當(dāng)隔離策略使用SEMAPHORE時(shí)捅位,最大的并發(fā)請(qǐng)求量,如果請(qǐng)求超過(guò)這個(gè)最大值將拒絕后續(xù)的請(qǐng)求搂抒,默認(rèn)值為10.
fallbackMethod
這個(gè)屬性就很好理解了绿渣,表示當(dāng)觸發(fā)隔離條件的時(shí)候會(huì)調(diào)用fallback設(shè)置的降級(jí)方法,在降級(jí)方法中燕耿,我們可以設(shè)置默認(rèn)的降級(jí)返回報(bào)文中符,這里需要注意的是降級(jí)方法的入?yún)⒑头祷刂敌枰驮椒ㄒ恢拢駝t在編譯的時(shí)候會(huì)報(bào)錯(cuò)誉帅。
Circuit Breaker熔斷器
circuitBreaker.requestVolumeThreshold
熔斷器在整個(gè)統(tǒng)計(jì)時(shí)間內(nèi)是否開(kāi)啟的閥值淀散,每個(gè)熔斷器默認(rèn)維護(hù)10個(gè)bucket,每秒一個(gè)bucket,每個(gè)bucket記錄成功,失敗,超時(shí),拒絕的狀態(tài),該閾值默認(rèn)20次蚜锨。也就是一個(gè)統(tǒng)計(jì)窗口時(shí)間內(nèi)(10秒鐘)至少請(qǐng)求20次档插,熔斷器才啟動(dòng)。
circuitBreaker.sleepWindowInMilliseconds
熔斷器默認(rèn)工作時(shí)間,默認(rèn)值為5秒.熔斷器中斷請(qǐng)求5秒后會(huì)進(jìn)入半打開(kāi)狀態(tài),放部分流量過(guò)去重試亚再,如果重試成功則會(huì)恢復(fù)正常請(qǐng)求郭膛。
circuitBreaker.errorThresholdPercentage
熔斷器錯(cuò)誤閾值,默認(rèn)為50%氛悬。當(dāng)在一個(gè)時(shí)間窗口內(nèi)出錯(cuò)率超過(guò)50%后熔斷器自動(dòng)啟動(dòng)则剃。熔斷器啟動(dòng)后交易會(huì)自動(dòng)轉(zhuǎn)發(fā)到HystrixCommand的run方法,即配置的fallbackMethod如捅,進(jìn)行降級(jí)處理棍现。但是在中斷開(kāi)啟后的sleepWindowInMilliseconds時(shí)間后會(huì)進(jìn)行半開(kāi)放狀態(tài),去正常請(qǐng)求镜遣,如果功能恢復(fù)則會(huì)自動(dòng)離開(kāi)熔斷狀態(tài)己肮,恢復(fù)正常請(qǐng)求處理。
circuitBreaker.forceOpen
熔斷器強(qiáng)制開(kāi)關(guān),如果設(shè)置為true則表示強(qiáng)制打開(kāi)熔斷器谎僻,所有請(qǐng)求都會(huì)拒絕娄柳,默認(rèn)為false。
circuitBreaker.forceClosed
與forceOpen正好相反艘绍。
ThreadPool Properties
coreSize
線程池核心線程數(shù)赤拒,默認(rèn)值為10,這里的含義和jdk的線程池一個(gè)意思鞍盗。
maxQueueSize
該參數(shù)表示配置線程值等待隊(duì)列長(zhǎng)度,默認(rèn)值:-1需了,建議值:-1表示不等待直接拒絕,測(cè)試表明線程池使用直接決絕策略+ 合適大小的非回縮線程池效率最高.所以不建議修改此值跳昼。 當(dāng)使用非回縮線程池時(shí)般甲,queueSizeRejectionThreshold,keepAliveTimeMinutes 參數(shù)無(wú)效。
queueSizeRejectionThreshold
表示等待隊(duì)列超過(guò)閾值后開(kāi)始拒絕線程請(qǐng)求鹅颊,默認(rèn)值為5敷存,如果maxQueueSize為1,則該屬性失效堪伍。