您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關(guān)SpringCloud-Hystrix實現(xiàn)原理是什么的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
(1) 服務(wù)降級
1)什么是服務(wù)降級
有了服務(wù)的熔斷,隨之就會有服務(wù)的降級,所謂服務(wù)降級,就是當(dāng)某個服務(wù)熔斷之后,服務(wù)端提供的服務(wù)將不再被調(diào)用,此時由客戶端自己準(zhǔn)備一個本地的fallback回調(diào),返回一個默認(rèn)值來代表服務(wù)端的返回;
這種做法,雖然不能得到正確的返回結(jié)果,但至少保證了服務(wù)的可用,比直接拋出錯誤或者服務(wù)不可用要好很多。
2)如何進行服務(wù)降級
(1)服務(wù)端
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è)務(wù)類
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值可以填寫方法的名字。
當(dāng)發(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> <!--一般基礎(chǔ)通用配置--> <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: true
3、主啟動
4、業(yè)務(wù)
@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 每個方法配置一個服務(wù)降級方法,技術(shù)上可以,實際上傻X
1:N 除了個別重要核心業(yè)務(wù)有專屬,其它普通的可以通過@DefaultProperties(defaultFallback = "") 統(tǒng)一跳轉(zhuǎn)到統(tǒng)一處理結(jié)果頁面
通用和獨享的各自分開,避免了代碼膨脹,合理減少了代碼量
(1) 程序運行異常 (當(dāng)我們把service方法中改成int i =10/0)
(2) 超時
(3) 服務(wù)熔斷觸發(fā)服務(wù)降級
(4) 線程池/信號量也會導(dǎo)致服務(wù)降級
(2) 服務(wù)熔斷
一、概念
(1)什么是服務(wù)熔斷
熔斷這一概念來源于電子工程中的斷路器(Circuit Breaker)。在互聯(lián)網(wǎng)系統(tǒng)中,當(dāng)下游服務(wù)因訪問壓力過大而響應(yīng)變慢或失敗,上游服務(wù)為了保護系統(tǒng)整體的可用性,可以暫時切斷對下游服務(wù)的調(diào)用。
在固定時間窗口內(nèi),接口調(diào)用超時比率達(dá)到一個閾值,會開啟熔斷。進入熔斷狀態(tài)后,后續(xù)對該服務(wù)接口的調(diào)用不再經(jīng)過網(wǎng)絡(luò),直接執(zhí)行本地的默認(rèn)方法,達(dá)到服務(wù)降級的效果。
熔斷不可能是永久的。當(dāng)經(jīng)過了規(guī)定時間之后,服務(wù)將從熔斷狀態(tài)回復(fù)過來,再次接受調(diào)用方的遠(yuǎn)程調(diào)用。
(2)熔斷的三種狀態(tài)
熔斷關(guān)閉狀態(tài)(Closed) 服務(wù)沒有故障時,熔斷器所處的狀態(tài),對調(diào)用方的調(diào)用不做任何限制。
熔斷開啟狀態(tài)(Open) 在固定時間窗口內(nèi)(Hystrix默認(rèn)是10秒),接口調(diào)用出錯比率達(dá)到一個閾值(Hystrix默認(rèn)為50),會進入熔斷開啟狀態(tài),進入熔斷狀態(tài)后,后續(xù)對該服務(wù)接口的調(diào)用不再經(jīng)過網(wǎng)絡(luò),直接執(zhí)行本地的fallback方法。
半熔斷狀態(tài)(half-open)哎進入熔斷開啟狀態(tài)一段時間之后(Hystrix默認(rèn)是5秒),熔斷器會進入半熔斷狀態(tài),所謂半熔斷就是嘗試恢復(fù)服務(wù)調(diào)用,允許有限的流量調(diào)用該服務(wù),并監(jiān)控調(diào)用成功率,如果成功率達(dá)到了預(yù)期,則說明服務(wù)已恢復(fù),進入熔斷關(guān)閉狀態(tài);如果成功率仍舊很低,則重新進入熔斷關(guān)閉狀態(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è)務(wù)
//====服務(wù)熔斷 @GetMapping("/payment/circuit/{id}") public String paymentCircuitBreaker(@PathVariable("id") Integer id) { String result = paymentService.paymentCircuitBreaker(id); log.info("****result: "+result); return result; }
//=====服務(wù)熔斷 @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"),// 失敗率達(dá)到多少后跳閘 }) public String paymentCircuitBreaker(@PathVariable("id") Integer id) { if(id < 0) { throw new RuntimeException("******id 不能負(fù)數(shù)"); } String serialNumber = IdUtil.simpleUUID(); return Thread.currentThread().getName()+"\t"+"調(diào)用成功,流水號: " + serialNumber; } public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id) { return "id 不能負(fù)數(shù),請稍后再試,/(ㄒoㄒ)/~~ id: " +id; }
涉及到斷路器的三個重要參數(shù):快照時間窗、請求總數(shù)閾值、錯誤百分比閾值
1:快照時間窗: 斷路器確定是否打開需要統(tǒng)計一些請求和錯誤數(shù)據(jù),而統(tǒng)計的時間范圍就是快照時間窗,默認(rèn)為最近的10秒。
2: 請求總數(shù)閾值: 在快照時間窗內(nèi),必須滿足請求總數(shù)閾值才有資格熔斷。默認(rèn)為20,意味著在10秒內(nèi),如果該hystrix命令的調(diào)用次數(shù)不足20次,即使所有的請求都超時或其他原因失敗,斷路器都不會打開。
3: 錯誤百分比閾值:當(dāng)請求總數(shù)在快照時間窗口內(nèi)超過了閾值,比如發(fā)生了30次調(diào)用,如果在這30次調(diào)用中,有15次發(fā)生了超時異常,也就是超過50%的錯誤百分比,在默認(rèn)設(shè)定50%閾值情況下,這時候就會將斷路器打開。
(3) 服務(wù)限流
1、限流概念
Hystrix把一個分布式系統(tǒng)的某一個服務(wù)打造成一個高可用的服務(wù)最重要的手段之一就是資源隔離,即通過限流來限制對某一服務(wù)的訪問量,比如說對Mysql的訪問,為了避免過大的流量直接請求mysql服務(wù),hstrix通過線程池或者信號量技術(shù)進行限流訪問。
我們了解到Hystrix的兩種隔離技術(shù):線程池和信號量。線程池和信號量,也分析了在什么樣的場景下使用線程池和信號量,通常來說線程池資源隔離技術(shù)一般用于對依賴服務(wù)的網(wǎng)絡(luò)請求訪問,需要解決timeout問題。信號量則適合對內(nèi)部的一些比較復(fù)雜的業(yè)務(wù)邏輯訪問,不涉及任何的網(wǎng)絡(luò)請求,當(dāng)并發(fā)量超過計數(shù)器指定值時,直接拒絕。
線程池隔離的最大優(yōu)點在于:任何一個依賴服務(wù)都可以被隔離在自己的線程池內(nèi),即使自己的線程池資源填滿了,也不會影響任何其他的服務(wù)調(diào)用。最大缺點在于:增加了cpu的開銷,除了tomcat本身的調(diào)用線程之外,還有hystrix自己管理的線程池。每個command的執(zhí)行都依托一個獨立的線程,會進行排隊,調(diào)度,還有上下文切換。
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(); }
當(dāng)請求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中調(diào)用
@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的使用個人總結(jié)
和一般的開箱即用工具類似,SpringCloud Hystrix只需要最多四步即可基本使用上
1. 引入依賴: spring-cloud-starter-hystrix
2. 添加支持: 在啟動類上添加@EnableHystrix
3. 具體使用: 在有熔斷需求的服務(wù)接口實現(xiàn)上標(biāo)注@HystrixCommand,指定發(fā)生熔斷時的回調(diào)方法
4. 按需配置: 比如配置熔斷時間
需要注意的是在具體使用環(huán)節(jié):
1. 回調(diào)方法必須在聲明@HystrixCommand的方法所在的類中,即回調(diào)方法必須是服務(wù)接口的兄弟方法
2. 回調(diào)方法的參數(shù)列表必須和服務(wù)接口的參數(shù)列表完全一致,否則報找不到回調(diào)方法異常.
回調(diào)方法保持與原接口參數(shù)列表強一致,說明回調(diào)方法就是原接口的替補接口,備胎接口.
通過對Hystrix的使用總結(jié),再次驗證了開箱即用工具的使用套路.
1.引入依賴
2.添加支持
3.具體使用
4.按需配置
感謝各位的閱讀!關(guān)于“SpringCloud-Hystrix實現(xiàn)原理是什么”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。