一柱锹、Hystrix簡(jiǎn)介
??在分布式環(huán)境中拜鹤,許多服務(wù)依賴項(xiàng)中的一些必然會(huì)失敗。Hystrix是一個(gè)庫(kù)钧舌,通過(guò)添加延遲容忍和容錯(cuò)邏輯担汤,幫助你控制這些分布式服務(wù)之間的交互。Hystrix通過(guò)隔離服務(wù)之間的訪問(wèn)點(diǎn)洼冻、停止級(jí)聯(lián)失敗和提供回退選項(xiàng)來(lái)實(shí)現(xiàn)這一點(diǎn)崭歧,所有這些都可以提高系統(tǒng)的整體彈性。
Hystrix如何解決依賴隔離:
1撞牢、包裹請(qǐng)求:使用HystrixCommand包裹對(duì)依賴的調(diào)用邏輯率碾,每個(gè)命令在獨(dú)立的線程中執(zhí)行,使用了設(shè)計(jì)模式中的“命令模式”屋彪;
2所宰、跳閘機(jī)制:當(dāng)某服務(wù)的錯(cuò)誤率超過(guò)一定閾值時(shí),Hystrix可以自動(dòng)或者手動(dòng)跳閘撼班,停止請(qǐng)求該服務(wù)一段時(shí)間歧匈;
3、資源隔離:Hystrix為每個(gè)依賴都維護(hù)了一個(gè)小型的線程池(或者信號(hào)量)砰嘁。如果該線程已滿件炉,則發(fā)向該依賴的請(qǐng)求就會(huì)被立即拒絕,而不是排隊(duì)等候矮湘,從而加速失敗判定斟冕;
4、監(jiān)控:Hystrix可以近乎實(shí)時(shí)地監(jiān)控運(yùn)行指標(biāo)和配置的變化缅阳,例如成功磕蛇、失敗、超時(shí)十办、以及被拒絕的請(qǐng)求等秀撇;
5、回退機(jī)制:當(dāng)請(qǐng)求失敗向族、超時(shí)呵燕、被拒絕,或當(dāng)斷路器打開時(shí)件相,執(zhí)行回退邏輯再扭,回退邏輯由開發(fā)人員自行提供氧苍,如返回一個(gè)缺省值;
6泛范、自我修復(fù):斷路器打開一段時(shí)間后让虐,會(huì)自動(dòng)進(jìn)入“半開”狀態(tài),此時(shí)斷路器可允許一個(gè)請(qǐng)求訪問(wèn)依賴的服務(wù)罢荡,若請(qǐng)求成功赡突,則斷路器關(guān)閉,否則斷路器轉(zhuǎn)為“打開”狀態(tài)柠傍;
形成過(guò)程:
1)服務(wù)提供者不可用
a)硬件故障:硬件損壞造成的服務(wù)器主機(jī)宕機(jī), 網(wǎng)絡(luò)硬件故障造成的服務(wù)提供者的不可訪問(wèn)
b)程序Bug:
c) 緩存擊穿:緩存擊穿一般發(fā)生在緩存應(yīng)用重啟, 所有緩存被清空時(shí),以及短時(shí)間內(nèi)大量緩存失效時(shí). 大量的緩存不命中, 使請(qǐng)求直擊后端,造成服務(wù)提供者超負(fù)荷運(yùn)行,引起服務(wù)不可用
d)用戶大量請(qǐng)求:在秒殺和大促開始前,如果準(zhǔn)備不充分,用戶發(fā)起大量請(qǐng)求也會(huì)造成服務(wù)提供者的不可用
2)重試加大流量
a)用戶重試:在服務(wù)提供者不可用后, 用戶由于忍受不了界面上長(zhǎng)時(shí)間的等待,而不斷刷新頁(yè)面甚至提交表單
b)代碼邏輯重試: 服務(wù)調(diào)用端的會(huì)存在大量服務(wù)異常后的重試邏輯
3)服務(wù)調(diào)用者不可用
a)同步等待造成的資源耗盡:當(dāng)服務(wù)調(diào)用者使用同步調(diào)用 時(shí), 會(huì)產(chǎn)生大量的等待線程占用系統(tǒng)資源. 一旦線程資源被耗盡,服務(wù)調(diào)用者提供的服務(wù)也將處于不可用狀態(tài), 于是服務(wù)雪崩效應(yīng)產(chǎn)生了麸俘。
??為了保證其高可用,單個(gè)服務(wù)通常會(huì)集群部署惧笛。由于網(wǎng)絡(luò)原因或者自身的原因从媚,服務(wù)并不能保證100%可用,如果單個(gè)服務(wù)出現(xiàn)問(wèn)題患整,調(diào)用這個(gè)服務(wù)就會(huì)出現(xiàn)線程阻塞拜效,此時(shí)若有大量的請(qǐng)求涌入,Servlet容器的線程資源會(huì)被消耗完畢各谚,導(dǎo)致服務(wù)癱瘓紧憾。服務(wù)與服務(wù)之間的依賴性,故障會(huì)傳播昌渤,會(huì)對(duì)整個(gè)微服務(wù)系統(tǒng)造成災(zāi)難性的嚴(yán)重后果赴穗,這就是服務(wù)故障的“雪崩”效應(yīng)。
Hystrix是一個(gè)用于分布式系統(tǒng)的延遲和容錯(cuò)的開源庫(kù)膀息。在分布式系統(tǒng)里般眉,許多依賴不可避免的調(diào)用失敗,比如超時(shí)潜支、異常等甸赃,Hystrix能夠保證在一個(gè)依賴出問(wèn)題的情況下,不會(huì)導(dǎo)致整個(gè)服務(wù)失敗冗酿,避免級(jí)聯(lián)故障埠对,以提高分布式系統(tǒng)的彈性。
服務(wù)雪崩
??多個(gè)微服務(wù)之間調(diào)用的時(shí)候裁替,假設(shè)微服務(wù)A調(diào)用微服務(wù)B和微服務(wù)C项玛,微服務(wù)B和微服務(wù)C有調(diào)用其他的微服務(wù),這就是所謂的”扇出”弱判,如扇出的鏈路上某個(gè)微服務(wù)的調(diào)用響應(yīng)式過(guò)長(zhǎng)或者不可用襟沮,對(duì)微服務(wù)A的調(diào)用就會(huì)占用越來(lái)越多的系統(tǒng)資源,進(jìn)而引起系統(tǒng)雪崩,所謂的”雪崩效應(yīng)”臣嚣。斷路器:
??“斷路器”本身是一種開關(guān)裝置,當(dāng)某個(gè)服務(wù)單元發(fā)生故障監(jiān)控(類似熔斷保險(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ù)熔斷:
??熔斷機(jī)制是應(yīng)對(duì)雪崩效應(yīng)的一種微服務(wù)鏈路保護(hù)機(jī)制,
??當(dāng)扇出鏈路的某個(gè)微服務(wù)不可用或者響應(yīng)時(shí)間太長(zhǎng)時(shí)座哩,會(huì)進(jìn)行服務(wù)的降級(jí)徒扶,進(jìn)而熔斷該節(jié)點(diǎn)微服務(wù)的調(diào)用,快速返回”錯(cuò)誤”的響應(yīng)信息根穷。當(dāng)檢測(cè)到該節(jié)點(diǎn)微服務(wù)響應(yīng)正常后恢復(fù)調(diào)用鏈路姜骡,在SpringCloud框架機(jī)制通過(guò)Hystrix實(shí)現(xiàn),Hystrix會(huì)監(jiān)控微服務(wù)見調(diào)用的狀況屿良,當(dāng)失敗的調(diào)用到一個(gè)閾值圈澈,缺省是5秒內(nèi)20次調(diào)用失敗就會(huì)啟動(dòng)熔斷機(jī)制,熔斷機(jī)制的注解是@HystrixCommand
二尘惧、Maven依賴
<!-- Hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
三康栈、 主啟動(dòng)類添加注解EnableCircuitBreaker
@SpringBootApplication
@EnableCircuitBreaker //對(duì)Hystrix熔斷機(jī)制的支持
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}
四、熔斷測(cè)試
@RequestMapping(value = "/user/get/{id}", method = RequestMethod.GET)
// 如果當(dāng)前調(diào)用的get()方法出現(xiàn)了錯(cuò)誤喷橙,則執(zhí)行fallback
@HystrixCommand(fallbackMethod="getFallback")
public Object get(@PathVariable("id") long id) {
String vo=null; // 接收數(shù)據(jù)庫(kù)的查詢結(jié)果
if (vo == null) { // 數(shù)據(jù)不存在啥么,假設(shè)讓它拋出個(gè)錯(cuò)誤
throw new RuntimeException("部門信息不存在!") ;
}
return vo ;
}
/**
* 此時(shí)方法的參數(shù) 與get()一致
* @param id
* @return
*/
public Object getFallback(@PathVariable("id") long id) {
User vo = new User() ;
vo.setId(1);
vo.setUsername("【ERROR】User-Service-Hystrix"); // 錯(cuò)誤的提示
return vo ;
}
現(xiàn)在的處理情況是:服務(wù)器出現(xiàn)了錯(cuò)誤(但并不表示提供方關(guān)閉)重慢,那么此時(shí)會(huì)調(diào)用指定方法的 fallback 處理饥臂。
什么情況下會(huì)觸發(fā)fallback方法?
名字 | 描述 | 觸發(fā)fallback |
---|---|---|
EMIT | 值傳遞NO | |
SUCCESS | 執(zhí)行完成似踱,沒(méi)有錯(cuò)誤 | NO |
FAILURE | 執(zhí)行拋出異常 | YES |
TIMEOUT | 執(zhí)行開始隅熙,但沒(méi)有在允許的時(shí)間內(nèi)完成 | YES |
BAD_REQUEST | 執(zhí)行拋出HystrixBadRequestException | NO |
SHORT_CIRCUITED | 斷路器打開核芽,不嘗試執(zhí)行 | YES |
THREAD_POOL_REJECTED | 線程池拒絕囚戚,不嘗試執(zhí)行 | YES |
SEMAPHORE_REJECTED | 信號(hào)量拒絕轧简,不嘗試執(zhí)行 | YES |
fallback方法在什么情況下會(huì)拋出異常
名字 | 描述 | 拋異常 |
---|---|---|
FALLBACK_EMIT | Fallback值傳遞 | NO |
FALLBACK_SUCCESS | Fallback執(zhí)行完成驰坊,沒(méi)有錯(cuò)誤 | NO |
FALLBACK_FAILURE | Fallback執(zhí)行拋出出錯(cuò) | YES |
FALLBACK_REJECTED | Fallback信號(hào)量拒絕,不嘗試執(zhí)行 | YES |
FALLBACK_MISSING | 沒(méi)有Fallback實(shí)例 | YES |
五、基于Feign使用Hystrix
通常情況下的Hystrix是通過(guò)注解@HystrixCommand的fallbackMethod屬性實(shí)現(xiàn)回調(diào)的,而在Feign中染服,由于Feign是用接口實(shí)現(xiàn)的聲明式Rest,所以Hystrix的通用方法在這里就不適用于Feign了益愈,實(shí)際上在Feign與SpringCloud的依賴庫(kù)中已經(jīng)默認(rèn)的將Hystrix加入其中了靠汁,如圖:
- Maven依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
- application.properties配置
server.port=8762
spring.application.name=user-service
#默認(rèn)feign的hystrix為關(guān)閉狀態(tài)
feign.hystrix.enabled=true
# 服務(wù)注冊(cè)
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
- 啟動(dòng)類
啟動(dòng)類添加@EnableFeignClients,控制層通過(guò)注入feign的接口去完成聲明式調(diào)用:
@SpringBootApplication
@EnableFeignClients
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
- 接口類
// 接口類上加入的注解中添加屬性fallback,指定回調(diào)類
@FeignClient(name = "USER-SERVICE",fallback = FeignClientFallback.class)
public interface UserFeign {
@RequestMapping("/getUser")
public String getUser();
}
- 回調(diào)類
/**
* @Description: 回調(diào)實(shí)現(xiàn)類
*/
@Component
class FeignClientFallback implements UserFeign {
@Override
public String getUser() {
System.out.println("熔斷,默認(rèn)回調(diào)函數(shù)");
return "{\"username\":\"admin\",\"age\":\"-1\"}";
}
}
6继薛、測(cè)試
@Autowired
private UserFeign userFeign;
@Test
public void getUser() {
String str = userFeign .getUser();
log.info("{}", str);
}
測(cè)試方法修壕,服務(wù)方法中,產(chǎn)生異常將會(huì)調(diào)用熔斷方法遏考。