SpringCloud-Hystrix實現(xiàn)原理總結
一、思維導圖

二、Hystrix包含的內容
(1) 服務降級
1)什么是服務降級
有了服務的熔斷,隨之就會有服務的降級,所謂服務降級,就是當某個服務熔斷之后,服務端提供的服務將不再被調用,此時由客戶端自己準備一個本地的fallback回調,返回一個默認值來代表服務端的返回;
這種做法,雖然不能得到正確的返回結果,但至少保證了服務的可用,比直接拋出錯誤或者服務不可用要好很多。
2)如何進行服務降級
(1)服務端
1、POM
<dependencies>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.tfjy.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>2、YML
server:
port: 8001
spring:
application:
name: cloud-provider-hystrix-payment
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
#defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
defaultZone: http://localhost:7001/eureka/3、主啟動
需要在主啟動上加上

4、業(yè)務類
controller
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
String result = paymentService.paymentInfo_TimeOut(id);
log.info("*****result"+result);
return result;
}service
@HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",commandProperties = {
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="5000")
})
public String paymentInfo_TimeOut(Integer id){
try{
TimeUnit.SECONDS.sleep(5);
}catch (InterruptedException e){
e.printStackTrace();
}
return "線程池:"+Thread.currentThread().getName()+"paymentInfo_TimeOut,id"+id+"O(∩_∩)O哈哈~"+"耗時5秒鐘";
}
public String paymentInfo_TimeOutHandler(Integer id){
return "線程池:"+Thread.currentThread().getName()+"paymentInfo_TimeOutHandler,id"+id+"o(╥﹏╥)o";
}在代碼上加上HystrixCommand注解,然后由個屬性fallbackMethod,value值可以填寫方法的名字。
當發(fā)生超時的時候,就會走下面的方法。

1、POM
<dependencies>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 引入自己定義的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>com.tfjy.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--一般基礎通用配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>2、YML
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://localhost:7001/eureka/
feign:
hystrix:
enabled: true3、主啟動

4、業(yè)務
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
@HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",commandProperties = {
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")
})
// @HystrixCommand
public String paymentInfo_TimeOut(@PathVariable("id") Integer id)
{
int age = 10/0;
String result = paymentHystrixService.paymentInfo_TimeOut(id);
return result;
}
public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id)
{
return "我是消費者80,對方支付系統(tǒng)繁忙請10秒鐘后再試或者自己運行出錯請檢查自己,o(╥﹏╥)o";
}
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class)
public interface PaymentHystrixService {
@GetMapping("/payment/hystrix/ok/{id}")
public String paymentInfo_ok(@PathVariable("id") Integer id);
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_TimeOut(@PathVariable("id") Integer id);
}這個參數(shù)要一樣
這個只能等待1.5s但是在8001要5s

三、全局配置
@RestController
@Slf4j
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public class OrderHystirxController {
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
// @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",commandProperties = {
// @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")
// })
@HystrixCommand
public String paymentInfo_TimeOut(@PathVariable("id") Integer id)
{
int age = 10/0;
String result = paymentHystrixService.paymentInfo_TimeOut(id);
return result;
}
public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id)
{
return "我是消費者80,對方支付系統(tǒng)繁忙請10秒鐘后再試或者自己運行出錯請檢查自己,o(╥﹏╥)o";
}
// 下面是全局fallback方法
public String payment_Global_FallbackMethod()
{
return "Global異常處理信息,請稍后再試,/(ㄒoㄒ)/~~";
}
}@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
1:1 每個方法配置一個服務降級方法,技術上可以,實際上傻
1:N 除了個別重要核心業(yè)務有專屬,其它普通的可以通過@DefaultProperties(defaultFallback = "") 統(tǒng)一跳轉到統(tǒng)一處理結果頁面
通用和獨享的各自分開,避免了代碼膨脹,合理減少了代碼量

三、哪些情況會發(fā)生服務降級
(1) 程序運行異常 (當我們把service方法中改成int i =10/0)
(2) 超時
(3) 服務熔斷觸發(fā)服務降級
(4) 線程池/信號量也會導致服務降級
(2) 服務熔斷
一、概念
(1)什么是服務熔斷
熔斷這一概念來源于電子工程中的斷路器(Circuit Breaker)。在互聯(lián)網(wǎng)系統(tǒng)中,當下游服務因訪問壓力過大而響應變慢或失敗,上游服務為了保護系統(tǒng)整體的可用性,可以暫時切斷對下游服務的調用。
在固定時間窗口內,接口調用超時比率達到一個閾值,會開啟熔斷。進入熔斷狀態(tài)后,后續(xù)對該服務接口的調用不再經過網(wǎng)絡,直接執(zhí)行本地的默認方法,達到服務降級的效果。
熔斷不可能是永久的。當經過了規(guī)定時間之后,服務將從熔斷狀態(tài)回復過來,再次接受調用方的遠程調用。
(2)熔斷的三種狀態(tài)

- 熔斷關閉狀態(tài)(Closed) 服務沒有故障時,熔斷器所處的狀態(tài),對調用方的調用不做任何限制。
- 熔斷開啟狀態(tài)(Open) 在固定時間窗口內(Hystrix默認是10秒),接口調用出錯比率達到一個閾值(Hystrix默認為50),會進入熔斷開啟狀態(tài),進入熔斷狀態(tài)后,后續(xù)對該服務接口的調用不再經過網(wǎng)絡,直接執(zhí)行本地的fallback方法。
- 半熔斷狀態(tài)(half-open)哎進入熔斷開啟狀態(tài)一段時間之后(Hystrix默認是5秒),熔斷器會進入半熔斷狀態(tài),所謂半熔斷就是嘗試恢復服務調用,允許有限的流量調用該服務,并監(jiān)控調用成功率,如果成功率達到了預期,則說明服務已恢復,進入熔斷關閉狀態(tài);如果成功率仍舊很低,則重新進入熔斷關閉狀態(tài)。
二、配置熔斷
(2)pom
<dependencies>
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency><!-- 引入自己定義的api通用包,可以使用Payment支付Entity -->
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>(2)YML
server:
port: 8001
spring:
application:
name: cloud-provider-hystrix-payment
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
#defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
defaultZone: http://eureka7001.com:7001/eureka(3)主啟動
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class PaymentHystrixMain8001
{
public static void main(String[] args) {
SpringApplication.run(PaymentHystrixMain8001.class, args);
}
}(4)業(yè)務
//====服務熔斷
@GetMapping("/payment/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id)
{
String result = paymentService.paymentCircuitBreaker(id);
log.info("****result: "+result);
return result;
}
//=====服務熔斷
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled",value = "true"),// 是否開啟斷路器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),// 請求次數(shù)
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), // 時間窗口期
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),// 失敗率達到多少后跳閘
})
public String paymentCircuitBreaker(@PathVariable("id") Integer id)
{
if(id < 0)
{
throw new RuntimeException("******id 不能負數(shù)");
}
String serialNumber = IdUtil.simpleUUID();
return Thread.currentThread().getName()+"\t"+"調用成功,流水號: " + serialNumber;
}
public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id)
{
return "id 不能負數(shù),請稍后再試,/(ㄒoㄒ)/~~ id: " +id;
}涉及到斷路器的三個重要參數(shù):快照時間窗、請求總數(shù)閾值、錯誤百分比閾值
1:快照時間窗: 斷路器確定是否打開需要統(tǒng)計一些請求和錯誤數(shù)據(jù),而統(tǒng)計的時間范圍就是快照時間窗,默認為最近的10秒。
2: 請求總數(shù)閾值: 在快照時間窗內,必須滿足請求總數(shù)閾值才有資格熔斷。默認為20,意味著在10秒內,如果該hystrix命令的調用次數(shù)不足20次,即使所有的請求都超時或其他原因失敗,斷路器都不會打開。
3: 錯誤百分比閾值:當請求總數(shù)在快照時間窗口內超過了閾值,比如發(fā)生了30次調用,如果在這30次調用中,有15次發(fā)生了超時異常,也就是超過50%的錯誤百分比,在默認設定50%閾值情況下,這時候就會將斷路器打開。
(3) 服務限流
1、限流概念
Hystrix把一個分布式系統(tǒng)的某一個服務打造成一個高可用的服務最重要的手段之一就是資源隔離,即通過限流來限制對某一服務的訪問量,比如說對Mysql的訪問,為了避免過大的流量直接請求mysql服務,hstrix通過線程池或者信號量技術進行限流訪問。
我們了解到Hystrix的兩種隔離技術:線程池和信號量。線程池和信號量,也分析了在什么樣的場景下使用線程池和信號量,通常來說線程池資源隔離技術一般用于對依賴服務的網(wǎng)絡請求訪問,需要解決timeout問題。信號量則適合對內部的一些比較復雜的業(yè)務邏輯訪問,不涉及任何的網(wǎng)絡請求,當并發(fā)量超過計數(shù)器指定值時,直接拒絕。
線程池隔離的最大優(yōu)點在于:任何一個依賴服務都可以被隔離在自己的線程池內,即使自己的線程池資源填滿了,也不會影響任何其他的服務調用。最大缺點在于:增加了cpu的開銷,除了tomcat本身的調用線程之外,還有hystrix自己管理的線程池。每個command的執(zhí)行都依托一個獨立的線程,會進行排隊,調度,還有上下文切換。
2、資源隔離
(1)線程隔離
Service
//------------------線程隔離
//groupKey 一組command ,如果沒有配這個,相同的groupkey會使用同一個線程池
@HystrixCommand(groupKey = "thread1-group",commandKey = "thread1",threadPoolKey = "thread1",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "30000")
},threadPoolProperties = {
@HystrixProperty(name = "coreSize",value = "3"),
@HystrixProperty(name = "maxQueueSize",value = "5")
})
public void thread1(){
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println(111);
}
System.out.println(Thread.currentThread().getName());
}controller
@GetMapping("getThread")
public void getThread(){
System.out.println(Thread.currentThread().getName());
paymentService.thread1();
}當請求getThread的時候
http-nio-8001-exec-1 hystrix-thread1-1 http-nio-8001-exec-3 hystrix-thread1-2
會發(fā)現(xiàn)兩個線程池是不一樣的。
我現(xiàn)在在service中再添加一個
//------------------線程隔離
//groupKey 一組command ,如果沒有配這個,相同的groupkey會使用同一個線程池
@HystrixCommand(groupKey = "thread1-group",commandKey = "thread1",threadPoolKey = "thread1",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
},threadPoolProperties = {
@HystrixProperty(name = "coreSize",value = "3"),
@HystrixProperty(name = "maxQueueSize",value = "5")
})
public void thread1(){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println(111);
}
System.out.println(Thread.currentThread().getName());
}
@HystrixCommand(groupKey = "thread2-group",commandKey = "thread2",threadPoolKey = "thread2",threadPoolProperties = {
@HystrixProperty(name = "coreSize",value = "3"),
@HystrixProperty(name = "maxQueueSize",value = "5"),
},commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1000")})
public void thread2(){
System.out.println(111);
System.out.println(Thread.currentThread().getName());
}在controller中調用
@GetMapping("getThread")
public void getThread(){
System.out.println(Thread.currentThread().getName());
paymentService.thread1();
paymentService.thread2();
}http-nio-8001-exec-1 hystrix-thread1-1 111 hystrix-thread2-1
@HystrixProperty(name = "coreSize",value = "3"), ## 這個表示核心線程數(shù) @HystrixProperty(name = "maxQueueSize",value = "5"), ## 這個表示這個隊列中的線程數(shù)為5個 所以這里面有8個
ps:下面看下對SpringCloud Hystrix的使用個人總結
和一般的開箱即用工具類似,SpringCloud Hystrix只需要最多四步即可基本使用上
1. 引入依賴: spring-cloud-starter-hystrix
2. 添加支持: 在啟動類上添加@EnableHystrix
3. 具體使用: 在有熔斷需求的服務接口實現(xiàn)上標注@HystrixCommand,指定發(fā)生熔斷時的回調方法
4. 按需配置: 比如配置熔斷時間
需要注意的是在具體使用環(huán)節(jié):
1. 回調方法必須在聲明@HystrixCommand的方法所在的類中,即回調方法必須是服務接口的兄弟方法
2. 回調方法的參數(shù)列表必須和服務接口的參數(shù)列表完全一致,否則報找不到回調方法異常.
回調方法保持與原接口參數(shù)列表強一致,說明回調方法就是原接口的替補接口,備胎接口.
通過對Hystrix的使用總結,再次驗證了開箱即用工具的使用套路.
1.引入依賴
2.添加支持
3.具體使用
4.按需配置
以上就是SpringCloud-Hystrix總結的詳細內容,更多關于SpringCloud-Hystrix總結的資料請關注腳本之家其它相關文章!
相關文章
String轉BigDecimal,BigDecimal常用操作,以及避免踩坑記錄
這篇文章主要介紹了String轉BigDecimal,BigDecimal常用操作,以及避免踩坑記錄,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07
解決Mybatis中mapper.xml文件update,delete及insert返回值問題
這篇文章主要介紹了解決Mybatis中mapper.xml文件update,delete及insert返回值問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11
Java List接口與Iterator接口及foreach循環(huán)使用解析
這篇文章主要介紹了Java List接口與Iterator接口及foreach循環(huán),主要包括List接口與Iterator接口及foreach循環(huán)具體的使用方法和代碼,需要的朋友可以參考下2022-04-04
SpringBoot+ShardingSphereJDBC實現(xiàn)讀寫分離詳情
這篇文章主要介紹了SpringBoot+ShardingSphereJDBC實現(xiàn)讀寫分離詳情,通過用??MySQL??進行一主一從的主從復制展開全文內容,需要的朋友可以參考一下2022-08-08

