SpringCloud中的Hystrix保護(hù)機(jī)制詳解
Hystrix簡(jiǎn)介
Hystrix,英文意思是豪豬,全身是刺,看起來(lái)就不好惹,是一種保護(hù)機(jī)制。
Hystrix也是Netflix公司的一款組件。
那么Hystix的作用是什么呢?具體要保護(hù)什么呢?
Hystix是Netflix開(kāi)源的一個(gè)延遲和容錯(cuò)庫(kù),用于隔離訪問(wèn)遠(yuǎn)程服務(wù)、第三方庫(kù),防止出現(xiàn)級(jí)聯(lián)失敗。
雪崩問(wèn)題
就好比,一個(gè)汽車(chē)生產(chǎn)線,生產(chǎn)不同的汽車(chē),需要使用不同的零件,如果某個(gè)零件因?yàn)榉N種原因無(wú)法使用,那么就會(huì)造成整臺(tái)車(chē)無(wú)法裝配,陷入等待零件的狀態(tài),直到零件到位,才能繼續(xù)組裝。
此時(shí)如果有很多個(gè)車(chē)型都需要這個(gè)零件,那么整個(gè)工廠都將陷入等待的狀態(tài),導(dǎo)致所有生產(chǎn)都陷入癱瘓。
一個(gè)零件的波及范圍不斷擴(kuò)大。
Hystix解決雪崩問(wèn)題的手段有兩個(gè):
- 線程隔離
- 服務(wù)熔斷
線程隔離,服務(wù)降級(jí)
Hystrix為每個(gè)依賴(lài)服務(wù)調(diào)用分配一個(gè)小的線程池,如果線程池已滿調(diào)用將被立即拒絕,默認(rèn)不采用排隊(duì).加速失敗判定時(shí)間。
用戶的請(qǐng)求將不再直接訪問(wèn)服務(wù),而是通過(guò)線程池中的空閑線程來(lái)訪問(wèn)服務(wù),如果線程池已滿,或者請(qǐng)求超時(shí),則會(huì)進(jìn)行降級(jí)處理,什么是服務(wù)降級(jí)?
服務(wù)降級(jí):優(yōu)先保證核心服務(wù),而非核心服務(wù)不可用或弱可用。
用戶的請(qǐng)求故障時(shí),不會(huì)被阻塞,更不會(huì)無(wú)休止的等待或者看到系統(tǒng)崩潰,至少可以看到一個(gè)執(zhí)行結(jié)果(例如返回友好的提示信息) 。
服務(wù)降級(jí)雖然會(huì)導(dǎo)致請(qǐng)求失敗,但是不會(huì)導(dǎo)致阻塞,而且最多會(huì)影響這個(gè)依賴(lài)服務(wù)對(duì)應(yīng)的線程池中的資源,對(duì)其它服務(wù)沒(méi)有響應(yīng)。
觸發(fā)Hystix服務(wù)降級(jí)的情況:
線程池已滿 請(qǐng)求超時(shí)
使用
使用hystrix步驟:
1.引入hystrix依賴(lài)
2.在啟動(dòng)類(lèi)上加@EnableCircuitBreaker注解開(kāi)啟隔離和熔斷
3.配置文件 配置超時(shí)時(shí)長(zhǎng) 不配置 也有默認(rèn)值
引入依賴(lài)
在消費(fèi)方引入依賴(lài)
<!--使用線程隔離和服務(wù)降級(jí)引入 hystrix依賴(lài)-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>開(kāi)啟隔離
在消費(fèi)者的啟動(dòng)類(lèi)上
//@EnableDiscoveryClient//開(kāi)啟負(fù)載均衡
//@EnableCircuitBreaker//開(kāi)啟服務(wù)隔離和熔斷
//@SpringBootApplication
@SpringCloudApplication//springCloud注解 包含了以上三個(gè)注解配置這個(gè)不需要配置以上三個(gè)注解
public class UserConsumerDemoApplication {
@Bean
@LoadBalanced//負(fù)載均衡的另一種使用方法 內(nèi)置一個(gè)攔截器 攔截所有restTemplate請(qǐng)求
public RestTemplate restTemplate() {
// 這次我們使用了OkHttp客戶端,只需要注入工廠即可
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(UserConsumerDemoApplication.class, args);
}
}@springCloud注解源碼
* @SpringBootApplication
* @EnableDiscoveryClient
* @EnableCircuitBreaker
* public @interface SpringCloudApplication {
* }編寫(xiě)降級(jí)邏輯
我們改造iconsumer,當(dāng)目標(biāo)服務(wù)的調(diào)用出現(xiàn)故障,我們希望快速失敗,給用戶一個(gè)友好提示。因此需要提前編寫(xiě)好失敗時(shí)的降級(jí)處理邏輯,要使用HystixCommond來(lái)完成
消費(fèi)者的控制層中
@RestController
@RequestMapping("/consumer")
@DefaultProperties(defaultFallback = "defaultFallBack")//默認(rèn)屬性 寫(xiě)在類(lèi)上 類(lèi)中所有方法通用屬性
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("{id}")
@HystrixCommand(fallbackMethod = "queryByIdFallBack")//開(kāi)啟線程隔離和降級(jí) fallbackMethod指定失敗方法
//類(lèi)上配置了 方法上直接配置@HystrixCommand注解就行
@HystrixCommand(commandProperties = { //配置單個(gè)方法的超時(shí)時(shí)間 配置整體的超時(shí)時(shí)間需要在配置文件中配置
//設(shè)置超時(shí)時(shí)長(zhǎng)為兩秒
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
})
public String queryById(@PathVariable("id") Long id){
String url="http://user-service/user/"+id;
String user = restTemplate.getForObject(url, String.class);
return user;
}
//失敗方法和成功方法 參數(shù) 返回值必須一樣 方法名不做限制
public String queryByIdFallBack(Long id){
return "服務(wù)正忙,稍后重試";
}
//在方法上配置寫(xiě)參數(shù) 在類(lèi)上配置通用的 不能寫(xiě)參數(shù)
public String defaultFallBack(){
return "服務(wù)正忙,稍后重試";
}改造服務(wù)提供者
改造userservice的控制層 觸發(fā)降級(jí)
@GetMapping("{id}")
public User queryUserById(@PathVariable("id") Long id) {
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return this.userService.queryUserById(id);
}
要注意,因?yàn)槿蹟嗟慕导?jí)邏輯方法必須跟正常邏輯方法保證:相同的參數(shù)列表和返回值聲明。失敗邏輯中返回User對(duì)象沒(méi)有太大意義,一般會(huì)返回友好提示。所以我們把queryById的方法改造為返回String,反正也是Json數(shù)據(jù)。這樣失敗邏輯中返回一個(gè)錯(cuò)誤說(shuō)明,會(huì)比較方便。
設(shè)置超時(shí)
在之前的案例中,請(qǐng)求在超過(guò)1秒后都會(huì)返回錯(cuò)誤信息,這是因?yàn)镠ystix的默認(rèn)超時(shí)時(shí)長(zhǎng)為1,我們可以通過(guò)配置修改這個(gè)值:
yaml配置
消費(fèi)者yaml中加入
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 6000 # 設(shè)置hystrix的超時(shí)時(shí)間為6000ms
服務(wù)熔斷
熔斷器,也叫斷路器,其英文單詞為:Circuit Breaker 。
熔斷狀態(tài)機(jī)3個(gè)狀態(tài):
Closed:關(guān)閉狀態(tài),所有請(qǐng)求都正常訪問(wèn)。
Open:打開(kāi)狀態(tài),所有請(qǐng)求都會(huì)被降級(jí)。Hystix會(huì)對(duì)請(qǐng)求情況計(jì)數(shù),當(dāng)一定時(shí)間內(nèi)失敗請(qǐng)求百分比達(dá)到閾值,則觸發(fā)熔斷,斷路器會(huì)完全打開(kāi)。默認(rèn)失敗比例的閾值是50%,請(qǐng)求次數(shù)最少不低于20次。
Half Open:半開(kāi)狀態(tài),open狀態(tài)不是永久的,打開(kāi)后會(huì)進(jìn)入休眠時(shí)間(默認(rèn)是5S)。隨后斷路器會(huì)自動(dòng)進(jìn)入半開(kāi)狀態(tài)。此時(shí)會(huì)釋放部分請(qǐng)求通過(guò),若這些請(qǐng)求都是健康的,則會(huì)完全關(guān)閉斷路器,否則繼續(xù)保持打開(kāi),再次進(jìn)行休眠計(jì)時(shí)
為了控制請(qǐng)求的成功或失敗,我們?cè)赾onsumer的控制層中加入一段邏輯:
public String queryById(@PathVariable("id") Long id){
//因?yàn)楹茈y模擬熔斷現(xiàn)象我們只能手動(dòng)控制 如果傳入的是偶數(shù)就熔斷 如果是技術(shù)就恢復(fù)正常
if(id%2==0){
throw new RuntimeException("");
}
String url="http://user-service/user/"+id;
String user = restTemplate.getForObject(url, String.class);
return user;
}@GetMapping("{id}")
// @HystrixCommand(fallbackMethod = "queryByIdFallBack")//開(kāi)啟線程隔離和降級(jí) fallbackMethod指定失敗方法
//類(lèi)上配置了 方法上直接配置@HystrixCommand注解就行
// @HystrixCommand(commandProperties = { //配置單個(gè)方法的超時(shí)時(shí)間 配置整體的超時(shí)時(shí)間需要在配置文件中配置
// //設(shè)置超時(shí)時(shí)長(zhǎng)為兩秒
// @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
// })
@HystrixCommand(
commandProperties = { //配置單個(gè)方法的超時(shí)時(shí)間 配置整體的超時(shí)時(shí)間需要在配置文件中配置
//設(shè)置熔斷器統(tǒng)計(jì)次數(shù)為10次
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),
//設(shè)置休眠時(shí)間窗為10秒
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"),
//設(shè)置錯(cuò)誤百分比 為百分之六十 十次失敗六次熔斷
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60")
})requestVolumeThreshold:觸發(fā)熔斷的最小請(qǐng)求次數(shù),默認(rèn)20
errorThresholdPercentage:觸發(fā)熔斷的失敗請(qǐng)求最小占比,默認(rèn)50%
sleepWindowInMilliseconds:休眠時(shí)長(zhǎng),默認(rèn)是5000毫秒
也可以在yaml配置文件中設(shè)置全局的時(shí)長(zhǎng)
hystrix:
command: #指令
default: #全局的
execution:
isolation:
thread:
timeoutInMilliseconds: 3000 #配置全局超時(shí)時(shí)長(zhǎng)為3秒到此這篇關(guān)于SpringCloud中的Hystrix保護(hù)機(jī)制詳解的文章就介紹到這了,更多相關(guān)SpringCloud的Hystrix內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Apache?Commons?Config管理配置文件核心功能使用
這篇文章主要為大家介紹了Apache?Commons?Config管理和使用配置文件核心深入探索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
java利用jieba進(jìn)行分詞的實(shí)現(xiàn)
本文主要介紹了在Java中使用jieba-analysis庫(kù)進(jìn)行分詞,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-03-03
SpringBoot項(xiàng)目引入token設(shè)置方式
本文詳細(xì)介紹了JWT(JSON Web Token)的基本概念、結(jié)構(gòu)、應(yīng)用場(chǎng)景以及工作原理,通過(guò)動(dòng)手實(shí)踐,展示了如何在Spring Boot項(xiàng)目中實(shí)現(xiàn)JWT的生成、驗(yàn)證和攔截器配置2025-01-01
SpringBoot使用Logback進(jìn)行日志記錄的代碼示例
在開(kāi)發(fā)Web應(yīng)用程序時(shí),日志記錄是非常重要的一部分,在SpringBoot中,我們可以使用Logback進(jìn)行日志記錄,Logback是一款高性能、靈活的日志框架,它可以滿足各種不同的日志需求,在本文中,我們介紹了如何在SpringBoot中使用Logback進(jìn)行日志記錄2023-06-06
Java實(shí)現(xiàn)從字符串中找出數(shù)字字符串的方法小結(jié)
這篇文章主要介紹了Java實(shí)現(xiàn)從字符串中找出數(shù)字字符串的方法,結(jié)合實(shí)例形式總結(jié)分析了Java查找數(shù)字字符串的常用技巧,需要的朋友可以參考下2016-03-03
如何解決springboot上傳文件路徑找不到的問(wèn)題
這篇文章主要介紹了如何解決springboot上傳文件路徑找不到的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-04-04
Java微信二次開(kāi)發(fā)(二) Java微信文本消息接口請(qǐng)求與發(fā)送
這篇文章主要為大家詳細(xì)介紹了Java微信二次開(kāi)發(fā)第二篇,Java微信文本消息接口請(qǐng)求與發(fā)送功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04
SpringBoot后端解決跨域問(wèn)題的3種方案分享
這篇文章主要給大家分享介紹了關(guān)于SpringBoot后端解決跨域問(wèn)題的3種方案,跨域指的是瀏覽器不能執(zhí)行其他網(wǎng)站的腳本,它是由瀏覽器的同源策略造成的,是瀏覽器施加的安全限制,需要的朋友可以參考下2023-07-07
springboot如何獲取yaml/yml(或properties)配置文件信息
在SpringBoot項(xiàng)目中,讀取配置文件信息是常見(jiàn)需求,可以通過(guò)@Autowired注入Environment類(lèi),使用@Value注解直接注入配置信息,或定義工具類(lèi)結(jié)合ApplicationRunner進(jìn)行高級(jí)配置信息獲取,特別提到2024-11-11

