SpringCloud hystrix服務(wù)降級(jí)概念介紹
Hystrix
初識(shí)Hystrix
Hystrix是什么?
Java應(yīng)用程序講求“高內(nèi)聚低耦合”,而spring cloud是一種微服務(wù)架構(gòu)理念,將原來(lái)的一個(gè)應(yīng)用程序拆分成許多微服務(wù)來(lái)調(diào)用,這樣的話就可以滿足“低耦合”的要求,但是隨之而來(lái)的就是“服務(wù)雪崩”問(wèn)題。
所謂的服務(wù)雪崩就是指,由于服務(wù)提供者不可用導(dǎo)致服務(wù)調(diào)用者不可用,并且在生產(chǎn)過(guò)程中,這種不可用逐漸擴(kuò)大的現(xiàn)象。想要解決“服務(wù)雪崩”問(wèn)題就需要用到Hystrix(豪豬)
Hystrix是一個(gè)用于處理分布式系統(tǒng)的延遲和容錯(cuò)的開(kāi)源庫(kù),在分布式系統(tǒng)里,許多依賴不可避免的會(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)中的蔓延,乃至雪崩。
Hystrix三大概念
服務(wù)降級(jí)(fallback)
fallback是什么
所謂的服務(wù)降級(jí)就是當(dāng)服務(wù)出現(xiàn)程序運(yùn)行異常、超時(shí)、服務(wù)熔斷觸發(fā)服務(wù)降級(jí)、線程池/信號(hào)量打滿等情況,此時(shí)應(yīng)該返回一個(gè)符合預(yù)期的、可處理的備選響應(yīng)(fallback),以提高用戶的使用體驗(yàn)而不是長(zhǎng)時(shí)間的等待請(qǐng)求或者返回一個(gè)超時(shí)異常頁(yè)面??偠灾?dāng)出現(xiàn)以上問(wèn)題時(shí),要有一個(gè)兜底方案來(lái)提高用戶的使用體驗(yàn)
服務(wù)降級(jí)的解決方案可以分為服務(wù)提供方和服務(wù)調(diào)用方,兩面都可以實(shí)現(xiàn)服務(wù)降級(jí)
服務(wù)提供方實(shí)現(xiàn)服務(wù)降級(jí)
第一步: 對(duì)服務(wù)提供方的service接口方法進(jìn)行加強(qiáng),主要就是針對(duì)可能出現(xiàn)超時(shí)等異常情況的接口,新建方法對(duì)其進(jìn)行兜底,如果原接口出現(xiàn)問(wèn)題則使用兜底方案進(jìn)行反饋
使用@HystrixCommand注解的fallbackMethod屬性指定兜底方法名,使用commandProperties屬性的@HystrixProperty注解指定異常類(lèi)型(超時(shí)異常和超時(shí)時(shí)間)
/**
* 超時(shí)訪問(wèn),設(shè)置自身調(diào)用超時(shí)的峰值,峰值內(nèi)正常運(yùn)行,超過(guò)了峰值需要服務(wù)降級(jí) 自動(dòng)調(diào)用fallbackMethod 指定的方法
* 超時(shí)異常或者運(yùn)行異常 都會(huì)進(jìn)行服務(wù)降級(jí)
* @param id
* @return
*/
@HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public String paymentInfoTimeOut(Integer id) {
int second = 5;
try {
TimeUnit.SECONDS.sleep(second);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "線程池: " + Thread.currentThread().getName() + " paymentInfoTimeOut,id: " + id + "\t"
+ "O(∩_∩)O哈哈~" + " 耗時(shí)(秒): " + second;
}
public String paymentInfo_TimeOutHandler(Integer id) {
return "超時(shí)異常兜底方案!線程池: " + Thread.currentThread().getName() + " paymentInfo_TimeOutHandler,id: " + id + "\t";
}第二步: 服務(wù)提供方的主啟動(dòng)類(lèi)上使用@EnableCircuitBreaker注解開(kāi)啟“熔斷器”,這樣的話前面的配置才能生效
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class HystrixPaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(HystrixPaymentMain8001.class, args);
}
}
除了上述可以自定義超時(shí)時(shí)間的異常,出現(xiàn)其他運(yùn)行時(shí)異常也會(huì)調(diào)用兜底方案返回

服務(wù)調(diào)用方實(shí)現(xiàn)服務(wù)降級(jí)
第一步: 使用配置文件開(kāi)啟hystrix
feign:
hystrix:
enabled: true
第二步: 服務(wù)調(diào)用方的controller加強(qiáng),新建方法對(duì)其進(jìn)行兜底,使用方式與服務(wù)提供方一樣,主要就是服務(wù)調(diào)用方和服務(wù)提供方兩套方案,可以實(shí)現(xiàn)兩邊定制化。
@GetMapping("/payment/hystrix/timeout/{id}")
@HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
})
public String paymentInfoTimeOut(@PathVariable("id") Integer id) {
String result = paymentHystrixService.paymentInfoTimeOut(id);
return result;
}
public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
return "服務(wù)調(diào)用方兜底方案!我是消費(fèi)者80,對(duì)方支付系統(tǒng)繁忙請(qǐng)10秒鐘后再試或者自己運(yùn)行出錯(cuò)請(qǐng)檢查自己,o(╥﹏╥)o";
}第三步: 服務(wù)調(diào)用方的主程序類(lèi)上使用@EnableHystrix注解開(kāi)啟hystrix
服務(wù)降級(jí)優(yōu)化
- 解決冗余問(wèn)題
前面的每一個(gè)方法都對(duì)應(yīng)一個(gè)兜底方案,這樣的話會(huì)顯得代碼十分臃腫,實(shí)際上很多的接口都可以使用一個(gè)兜底方案,于是我們就可以配置默認(rèn)的兜底方案,在沒(méi)有使用@HystrixCommand注解指定的時(shí)候,類(lèi)中的所有接口都會(huì)走默認(rèn)兜底方案
@DefaultProperties注解的defaultFallback屬性指定默認(rèn)兜底方法,如果類(lèi)中存在@HystrixCommand注解中不使用屬性指定特定兜底方案的情況,就說(shuō)明這個(gè)接口使用是默認(rèn)兜底方案
@RestController
@RequestMapping("consumer")
@Slf4j
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public class OrderHystrixController {
@Resource
private PaymentHystrixService paymentHystrixService;
@HystrixCommand
@GetMapping("/payment/hystrix/ex/{id}")
public String paymentInfoException(@PathVariable("id") Integer id) {
int age = 10/0;
String result = paymentHystrixService.paymentInfoException(id);
return result;
}
/**
* hystrix 全局fallback方法
* @return
*/
public String payment_Global_FallbackMethod() {
return "Global異常處理信息,請(qǐng)稍后再試,/(ㄒoㄒ)/~~";
}
}- 解決耦合問(wèn)題
上述操作中,原方案和兜底方案都在controller中定義,想要解決這個(gè)耦合問(wèn)題可以使用一個(gè)類(lèi)實(shí)現(xiàn)service接口,然后重寫(xiě)所有的接口方法,然后使用service接口上@FeignClient注解的fallback屬性指定接口的實(shí)現(xiàn)類(lèi)為兜底類(lèi)
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT", fallback = PaymentFallbackService.class)
public interface PaymentHystrixService {
@GetMapping("/payment/hystrix/ok/{id}")
String paymentInfoOK(@PathVariable("id") Integer id);
@GetMapping("/payment/hystrix/timeout/{id}")
String paymentInfoTimeOut(@PathVariable("id") Integer id);
@GetMapping("/payment/hystrix/ex/{id}")
String paymentInfoException(Integer id);
}
@Component
public class PaymentFallbackService implements PaymentHystrixService {
@Override
public String paymentInfoOK(Integer id) {
return "-----PaymentFallbackService fall back-paymentInfo_OK ,o(╥﹏╥)o";
}
@Override
public String paymentInfoTimeOut(Integer id) {
return "-----PaymentFallbackService fall back-paymentInfo_TimeOut ,o(╥﹏╥)o";
}
@Override
public String paymentInfoException(Integer id) {
return "-----PaymentFallbackService fall back-paymentInfoException ,o(╥﹏╥)o";
}
}服務(wù)熔斷(break)
break是什么
微服務(wù)鏈路中某個(gè)微服務(wù)的請(qǐng)求達(dá)到最大訪問(wèn)之后,直接拒絕訪問(wèn),然后調(diào)用服務(wù)降級(jí)的方法返回友好的提示;當(dāng)檢測(cè)到該節(jié)點(diǎn)微服務(wù)調(diào)用響應(yīng)正常之后,還可以恢復(fù)鏈路的正常調(diào)用。hystrix會(huì)默認(rèn)在服務(wù)5秒內(nèi)調(diào)用失敗20次后觸發(fā)熔斷機(jī)制,但是也可以使用配置對(duì)其進(jìn)行修改。
服務(wù)提供方實(shí)現(xiàn)服務(wù)熔斷
首先service層使用注解配置服務(wù)熔斷的相關(guān)值和熔斷時(shí)的備選方案,就以下代碼為例:在10S的時(shí)間窗口期中,10次請(qǐng)求中失敗率達(dá)到60%就會(huì)觸發(fā)熔斷啟動(dòng)備選方案。
如果在10S的時(shí)間窗口期中,請(qǐng)求次數(shù)不足10次,那么根本就不可能觸發(fā)熔斷器。當(dāng)熔斷器開(kāi)啟后所有的請(qǐng)求都不會(huì)被轉(zhuǎn)發(fā),一段時(shí)間窗口期之后(默認(rèn)5秒,可以自定義配置)斷路器切換為半開(kāi)狀態(tài),此時(shí)會(huì)讓其中一個(gè)請(qǐng)求進(jìn)行轉(zhuǎn)發(fā),成功則關(guān)閉斷路器,反之繼續(xù)開(kāi)啟
@HystrixCommand(fallbackMethod = "paymentCircuitBreakerFallback", 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ù)");
}
String serialNumber = IdUtil.simpleUUID();
return Thread.currentThread().getName() + "\t" + "調(diào)用成功,流水號(hào): " + serialNumber;
}
public String paymentCircuitBreakerFallback(Integer id) {
return Thread.currentThread().getName() + "\t" + "id 不能負(fù)數(shù)或超時(shí)或自身錯(cuò)誤,請(qǐng)稍后再試,/(ㄒoㄒ)/~~ id: " + id;
}controller中調(diào)用service方法
@GetMapping("/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
String result = paymentService.paymentCircuitBreaker(id);
log.info("****result: " + result);
return result;
}服務(wù)限流(flowlimit)
flowlimit是什么
在秒殺等高并發(fā)的操作下,為了防止大量請(qǐng)求一塊發(fā)送過(guò)來(lái),采用排隊(duì)的方式,把請(qǐng)求按照順序排隊(duì)發(fā)送過(guò)來(lái)。由于hystrix已經(jīng)停止更新,而且Alibaba的sentinel在進(jìn)行服務(wù)限流的處理時(shí)比hystrix更加優(yōu)秀,所以說(shuō)這一部分知識(shí)可以放在后面進(jìn)行學(xué)習(xí)。
Hystrix圖形化監(jiān)控
第一步: 新建一個(gè)模塊用于監(jiān)控,導(dǎo)入相關(guān)依賴
<dependencies>
<!--最主要的依賴,用于引入圖形化dashboard-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<!-- 引入自己定義的api通用包 -->
<dependency>
<groupId>com.xiaochen</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>第一步: 配置文件配置端口號(hào)
server:
port: 9001
第三步: 主啟動(dòng)類(lèi)開(kāi)啟HystrixDashboard,
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardMain9001 {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardMain9001.class, args);
}
}
此外,所有的服務(wù)提供方也就是被監(jiān)控的服務(wù)都要引入spring-boot-starter-actuator依賴,表示自己可以受監(jiān)控。然后就是在服務(wù)的主啟動(dòng)類(lèi)上要使用以下代碼中的addUrlMappings配置受監(jiān)控的路徑
/**
* 注意:新版本Hystrix需要在主啟動(dòng)類(lèi)中指定監(jiān)控路徑
* 此配置是為了服務(wù)監(jiān)控而配置,與服務(wù)容錯(cuò)本身無(wú)關(guān),spring cloud升級(jí)后的坑
* ServletRegistrationBean因?yàn)閟pringboot的默認(rèn)路徑不是"/hystrix.stream",
* 只要在自己的項(xiàng)目里配置上下面的servlet就可以了
*
* @return ServletRegistrationBean
*/
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
// 一啟動(dòng)就加載
registrationBean.setLoadOnStartup(1);
// 添加url
registrationBean.addUrlMappings("/hystrix.stream");
// 設(shè)置名稱(chēng)
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}啟動(dòng)監(jiān)控模塊、eureka模塊、受監(jiān)控模塊之后,訪問(wèn)以下路徑可以通過(guò)路徑監(jiān)控指定的服務(wù),設(shè)置后點(diǎn)擊下面的Monitor Stream按鈕即可進(jìn)入圖形化監(jiān)控界面

圖形化界面各處代表的含義如下:

到此這篇關(guān)于SpringCloud hystrix服務(wù)降級(jí)概念介紹的文章就介紹到這了,更多相關(guān)SpringCloud hystrix內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringCloud Feign隔離與降級(jí)詳細(xì)分析
- SpringCloud hystrix服務(wù)降級(jí)學(xué)習(xí)筆記
- SpringCloud?hystrix斷路器與局部降級(jí)全面介紹
- SpringCloud降級(jí)規(guī)則使用介紹
- SpringCloud-Alibaba-Sentinel服務(wù)降級(jí),熱點(diǎn)限流,服務(wù)熔斷
- springcloud 服務(wù)降級(jí)的實(shí)現(xiàn)方法
- 詳解springcloud 基于feign的服務(wù)接口的統(tǒng)一hystrix降級(jí)處理
- springcloud使用Hystrix進(jìn)行微服務(wù)降級(jí)管理
- SpringCloud災(zāi)難性雪崩效應(yīng)處理方法之降級(jí)實(shí)現(xiàn)流程詳解
相關(guān)文章
Java如何在沙箱環(huán)境中測(cè)試支付寶支付接口
這篇文章主要介紹了Java如何在沙箱環(huán)境中測(cè)試支付寶支付接口,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
java servlet結(jié)合Oracle搭建java的web開(kāi)發(fā)環(huán)境
今天我將與大家分享一下我學(xué)JAVA WEB寫(xiě)的一些小實(shí)例 ,我個(gè)人是不太喜歡書(shū)本上的晦澀的概念的,所以我花了更多的時(shí)間在一些應(yīng)用實(shí)例上,我覺(jué)得這樣的學(xué)習(xí)方式很適合我,由簡(jiǎn)到繁,由淺入深2015-12-12
Mybatis-Plus動(dòng)態(tài)表名的實(shí)現(xiàn)示例
面對(duì)復(fù)雜多變的業(yè)務(wù)需求,動(dòng)態(tài)表名的處理變得愈發(fā)重要,本文主要介紹了Mybatis-Plus動(dòng)態(tài)表名的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2024-07-07
spring,mybatis事務(wù)管理配置與@Transactional注解使用詳解
這篇文章主要介紹了spring,mybatis事務(wù)管理配置與@Transactional注解使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
Java(SpringBoot)項(xiàng)目打包(構(gòu)建)成Docker鏡像的幾種常見(jiàn)方式
在對(duì)Spring Boot應(yīng)用程序進(jìn)行Docker化時(shí),為應(yīng)用程序選擇正確的基礎(chǔ)鏡像非常重要,下面這篇文章主要給大家介紹了關(guān)于Java(SpringBoot)項(xiàng)目打包(構(gòu)建)成Docker鏡像的幾種常見(jiàn)方式,需要的朋友可以參考下2023-12-12
SpringBoot集成Mybatis過(guò)程步驟圖解
這篇文章主要介紹了SpringBoot集成Mybatis過(guò)程步驟圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07
Java(TM) Platform SE binary 打開(kāi)jar文件的操作
這篇文章主要介紹了Java(TM) Platform SE binary 打開(kāi)jar文件的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02

