概述
Hystrix是一個(gè)用于處理分布式系統(tǒng)的延遲和容錯(cuò)的開(kāi)元庫(kù),在分布式系統(tǒng)里,許多以來(lái)不可避免的會(huì)調(diào)用失敗,比如超時(shí),異常等,Hystrix能夠保證在一個(gè)依賴出問(wèn)題的情況下,不會(huì)導(dǎo)致整體服務(wù)失敗,避免級(jí)聯(lián)鼓掌,以提高分布式系統(tǒng)的彈性
"斷路器"本身是一種開(kāi)關(guān)裝置,當(dāng)某個(gè)服務(wù)單元發(fā)生故障之后,通過(guò)斷路器的鼓掌監(jiān)控(類(lèi)似熔斷保險(xiǎn)絲),想調(diào)用方返回一個(gè)符合預(yù)期的,可處理的備選響應(yīng)(FallBack),而不是長(zhǎng)時(shí)間的等待或者跑出調(diào)用方無(wú)法處理的異常,這樣就保證了服務(wù)調(diào)用方的線程不會(huì)被長(zhǎng)時(shí)間,不必要的占用,從而避免了故障在分布式系統(tǒng)中的蔓延,乃至雪崩.
主要做的是
- 服務(wù)熔斷
類(lèi)似保險(xiǎn)絲達(dá)到最大服務(wù)訪問(wèn)后,直接拒絕訪問(wèn),拉閘限電,然后調(diào)用服務(wù)降級(jí)的方法并返回友好提示
- 服務(wù)降級(jí)
程序運(yùn)行異常,超時(shí),服務(wù)熔斷出發(fā)服務(wù)降級(jí),線程池/信號(hào)量打滿也會(huì)導(dǎo)致服務(wù)降級(jí).服務(wù)器忙,請(qǐng)稍后再試,不讓客戶端等待并立刻返回一個(gè)友好提示,fallback
- 服務(wù)限流
秒殺高并發(fā)等操作,嚴(yán)禁一窩蜂的過(guò)來(lái)?yè)頂D,大家排隊(duì),一秒鐘N個(gè),有序進(jìn)行
- 接近實(shí)時(shí)的監(jiān)控
實(shí)操
構(gòu)建
- 引入jar包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
高并發(fā)測(cè)試
在使用我們的jmeter200線程,200輪次的2w次請(qǐng)求同一耗時(shí)比較慢的接口時(shí)
public String paymentInfo_error(Integer id) {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "線程池" + Thread.currentThread().getName() + "\t" + id + "\t" + "^_^" + "耗時(shí)3秒鐘";
}
這個(gè)時(shí)候,即使訪問(wèn)比較快的方法,也會(huì)受到拖累,因?yàn)閠omcat默認(rèn)200個(gè)線程,因?yàn)樯鲜龇椒▓?zhí)行時(shí),多數(shù)線程都被調(diào)用去擁擠到那兒去執(zhí)行滿方法,導(dǎo)致我們?cè)菊5姆?wù)也會(huì)被變慢
public String paymentInfo_OK(Integer id) {
return "線程池" + Thread.currentThread().getName() + "\t" + id + "\t" + "^_^";
}
hyxtrix如何解決
降級(jí)處理緯度
- 服務(wù)端down機(jī),不能讓客戶端一直等待,必須有服務(wù)降級(jí)(選擇較多)
- 對(duì)方服務(wù)執(zhí)行成功,但時(shí)間大于我所期待的時(shí)間,自己做服務(wù)降級(jí)處理
- 服務(wù)端處理
在主啟動(dòng)類(lèi)上加上開(kāi)啟配置注解
@EnableCircuitBreaker
在可能出錯(cuò)的業(yè)務(wù)類(lèi)中添加服務(wù)降級(jí)fallback方法,并指定
/**
* @HystrixCommand 指定fallback降級(jí)方法
* @HystrixProperty 指定峰值等待時(shí)間
*/
@HystrixCommand(fallbackMethod = "paymentInfo_error_timeOutHandler", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")})
public String paymentInfo_error(Integer id) {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "線程池" + Thread.currentThread().getName() + "\t" + id + "\t" + "^_^" + "耗時(shí)5秒鐘";
}
public String paymentInfo_error_timeOutHandler(Integer id) {
return "線程池" + Thread.currentThread().getName() + "\t" + id + "\t" + "┭┮﹏┭┮" + "8001服務(wù)超時(shí)";
}
- 客戶端處理(openFeign+hyxtrix)
主啟動(dòng)類(lèi)加載開(kāi)啟配置注解
@EnableHystrix
yml配置文件開(kāi)啟hyxtrix
feign:
hystrix:
enabled: true
控制層添加fallback方法并指定
/**
* @HystrixCommand 指定fallback降級(jí)方法
* @HystrixProperty 指定峰值等待時(shí)間
*/
@GetMapping("error/{id}")
@HystrixCommand(fallbackMethod = "paymentInfo_error_timeOutHandler", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000")})
public String error(@PathVariable("id") Integer id) {
return feignService.error(id);
}
public String paymentInfo_error_timeOutHandler(Integer id) {
return "線程池" + Thread.currentThread().getName() + "\t" + id + "\t" + "┭┮﹏┭┮" + "80服務(wù)超時(shí)";
}
全局服務(wù)降級(jí)配置
由于每個(gè)方法都要配置一個(gè)fallback,導(dǎo)致代碼膨脹和麻煩,所以我們可以定義一個(gè)全局通用的服務(wù)降級(jí)處理,和自定義分開(kāi)
- 再需要做服務(wù)降級(jí)的restControll上加上全局降級(jí)配置注解(defaultFallback參數(shù)為,類(lèi)中的共享fallback方法名)
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
- 再需要做服務(wù)降級(jí)的方法上,加上服務(wù)降級(jí)處理,并不需要加參數(shù),默認(rèn)走我們的全局服務(wù)降級(jí)處理
@HystrixCommand
全局服務(wù)降級(jí)配置(二)
由于業(yè)務(wù)不同,需要考慮解耦性的情況下,對(duì)于一個(gè)服務(wù)調(diào)用接口,再不同的controller里都有用到,那么對(duì)每一個(gè)controller進(jìn)行配置,也會(huì)增加耦合性,所以也有另一種方式來(lái)實(shí)現(xiàn)這種情況
- 針對(duì)于服務(wù)發(fā)現(xiàn)接口類(lèi)去實(shí)現(xiàn)一個(gè)專(zhuān)門(mén)去配置fallback的類(lèi),并實(shí)現(xiàn)他們的接口方法
- 并在接口上的Fileclent注解上,指定這個(gè)class為,服務(wù)調(diào)用失敗統(tǒng)一的fallback處理
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = FeignFallbackServiceImpl.class)
服務(wù)熔斷
服務(wù)熔斷類(lèi)比保險(xiǎn)絲達(dá)到最大服務(wù)訪問(wèn)后,直接拒絕訪問(wèn),拉閘限電,然后調(diào)用服務(wù)降級(jí)的方法并返回友好提示
熔斷機(jī)制是應(yīng)對(duì)雪崩效應(yīng)的一種微服務(wù)鏈路保護(hù)機(jī)制,當(dāng)扇出鏈路的某個(gè)微服務(wù)出錯(cuò)不可用或者訪問(wèn)時(shí)間太長(zhǎng)時(shí)間,會(huì)進(jìn)行服務(wù)的降級(jí),勁兒熔斷該節(jié)點(diǎn)微服務(wù)的調(diào)用,快速返回錯(cuò)誤的響應(yīng)信息
在Spring Cloud框架里,熔斷機(jī)制通過(guò)Hystrix實(shí)現(xiàn),Hystrix會(huì)監(jiān)控微服務(wù)之間的調(diào)用狀況,當(dāng)失敗的調(diào)用到一定閾值,缺省是五秒內(nèi)20次調(diào)用失敗,就會(huì)啟動(dòng)熔斷機(jī)制,熔斷機(jī)制.當(dāng)檢測(cè)到該節(jié)點(diǎn)微服務(wù)調(diào)用響應(yīng)正常后,恢復(fù)調(diào)用鏈路
實(shí)現(xiàn)
在需要服務(wù)熔斷的接口上添加服務(wù)熔斷注解
// =============服務(wù)熔斷
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled",value = "true"),//是否開(kāi)啟斷路器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),//請(qǐng)求次數(shù)
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"),//時(shí)間范圍
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60")//失敗率%達(dá)到多少后跳閘
})
public String paymentCircuitBreaker(Integer id) {
if (id < 0) {
throw new RuntimeException("id 不能負(fù)數(shù)");
}
return Thread.currentThread().getName() + "\t" + "調(diào)用成功,流水號(hào): " + IdUtil.fastSimpleUUID();
}
其他配置可參考HystrixCommandProperties類(lèi),有詳細(xì)參數(shù)
總結(jié)
服務(wù)熔斷器是,當(dāng)我們?cè)O(shè)定好的閾值達(dá)到了,便進(jìn)行服務(wù)熔斷的機(jī)制,再次重復(fù)調(diào)用直接返回fallback服務(wù)降級(jí)處理,根據(jù)內(nèi)部算法慢慢的將服務(wù)進(jìn)行恢復(fù)正臣值耄可調(diào)用狀態(tài)