SpringCloud(7) - Hystrix熔斷器
一、前言
1)分散式系統面臨的問題
複雜分散式體系結構中的應用程式有數十個依賴關係,每個依賴關係在某些時候將不可避免地失敗!
當一切正常時,請求看起來是這樣的:
當其中有一個系統有延遲時,它可能阻塞整個使用者請求:
2)服務雪崩
多個微服務之間呼叫的時候,假設微服務A呼叫微服務B和微服務C,微服務B和微服務C又呼叫其它的微服務,這就是所謂的“扇出”。如果扇出的鏈路上某個微服務的呼叫響應時間過長或者不可用,對微服務A的呼叫就會佔用越來越多的系統資源,進而引起系統崩潰,所謂的“雪崩效應”。
對於高流量的應用來說,單一的後端依賴可能會導致所有伺服器上的所有資源都在幾秒鐘內飽和。比失敗更糟糕的是,這些應用程式還可能導致服務之間的延遲增加,備份佇列,執行緒和其他系統資源緊張,導致整個系統發生更多的級聯故障。這些都表示需要對故障和延遲進行隔離和管理,以便單個依賴關係的失敗,不能取消整個應用程式或系統。
3)什麼是Hystrix
Hystrix是一個用於處理分散式系統的延遲和容錯的開源庫,在分散式系統裡,許多依賴不可避免的會呼叫失敗,比如超時、異常等,Hystrix能夠保證在一個依賴出問題的情況下,不會導致整體服務失敗,避免級聯故障,以提高分散式系統的彈性。
“斷路器”本身是一種開關裝置,當某個服務單元發生故障之後,通過斷路器的故障監控(類似熔斷保險絲),向呼叫方返回一個符合預期的、可處理的備選響應(FallBack),而不是長時間的等待或者丟擲呼叫方無法處理的異常,這樣就保證了服務呼叫方的執行緒不會被長時間、不必要地佔用,從而避免了故障在分散式系統中的蔓延,乃至雪崩。
4)Hystrix能幹什麼
① 服務降級
② 服務熔斷
③ 服務限流
④ 接近實時的監控
⑤ …
二、服務熔斷
熔斷機制是應對雪崩效應的一種微服務鏈路保護機制
當扇出鏈路的某個微服務不可用或者響應時間太長時,會進行服務的降級,進而熔斷該節點微服務的呼叫,快速返回”錯誤”的響應資訊。當檢測到該節點微服務響應正常後恢復呼叫鏈路,在 SpringCloud 框架機制通過Hystrix實現,Hystrix 會監控微服務見呼叫的狀況,當失敗的呼叫到一個閾值,預設是5秒內20次呼叫失敗就會啟動熔斷機制,熔斷機制的註解是 @HystrixCommand
1)程式碼實現
新建一個服務提供者模組 spirngcloud-provider-dept-hystrix-8001
內容保持和 spirngcloud-provider-dept-8001相同,修改主啟動類的類名和 yaml 中的 instance-id
① 匯入 Hystrix 的依賴
<!--hystrix--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> <version>1.4.6.RELEASE</version> </dependency>
② 把之前的 Controller 中的程式碼刪掉,重新編寫
@RestController public class DeptController { @Autowired public DeptService deptService; @RequestMapping("/dept/get/{id}") @HystrixCommand(fallbackMethod = "hystrixGet") // 使用HystrixCommand註解,在fallbackMethod屬性中指定fallback的方法 public Dept get(@PathVariable("id") Long id) { Dept dept = deptService.queryById(id); if (dept == null) { throw new RuntimeException("id => " + id + ",不存在該使用者或者資訊找不到!!!"); } return dept; } // 備選方案:覆寫fallbackMethod中指定的方法,注意,此方法的返回值,引數必須與原方法一致 public Dept hystrixGet(@PathVariable("id") Long id) { return new Dept() .setDeptno(id) .setDname("id => " + id + ",不存在該使用者或者資訊找不到!!!") .setDb_source("no database in MySQL!!!"); } }
③ 在主啟動類新增對熔斷的支援 @EnableCircuitBreaker
// 啟動類 @SpringBootApplication @EnableEurekaClient // 在服務啟動後自動註冊到Eureka中 @EnableDiscoveryClient // 服務發現 @EnableCircuitBreaker // 新增對熔斷的支援 public class DeptProviderHystrix_8001 { public static void main(String[] args) { SpringApplication.run(DeptProviderHystrix_8001.class, args); } }
④ 啟動測試
這樣,在訪問 localhost/consumer/queryById/123456789時,因為此id不存在,所以會出現異常,這樣就呼叫了我們備用的方法
三、服務降級
服務降級,當伺服器壓力劇增的情況下,根據當前業務情況及流量對一些服務和頁面有策略的降級,以此釋放伺服器資源以保證核心任務的正常執行。比如電商平臺,在針對618、雙11等高峰情形下采用部分服務不出現或者延時出現的情形。
1)程式碼實現
在 springcloud-api 模組中,新建一個類 DeptClientServiceFallbackFactory,實現 FallbackFactory 介面,並添加註解 @Component,將該類放入 IOC 中,實現其中的方法
// 服務降級 @Component public class DeptClientServiceFallBackFactory implements FallbackFactory { @Override public DeptClientService create(Throwable throwable) { return new DeptClientService() { @Override public Dept queryById(Long id) { return new Dept() .setDeptno(id) .setDname("id==>" + id + ",沒有對應的資訊,客戶端提供了降級的資訊,這個服務現在已經被關閉") .setDb_source("沒有資料"); } @Override public List<Dept> queryAll() { return null; } @Override public boolean addDept(Dept dept) { return false; } }; } }
在 DeptClientService介面上,添加註解 @FeignClient(fallbackFactory = DeptClientServiceFallbackFactory.class)
@Component @FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT", fallbackFactory = DeptClientServiceFallBackFactory.class) public interface DeptClientService { @GetMapping("/dept/get/{id}") public Dept queryById(@PathVariable("id") Long id); @GetMapping("/dept/list") public List<Dept> queryAll(); @GetMapping("/dept/add") public boolean addDept(Dept dept); }
在 springcloud-consumer-dept-feign模組的 yaml 中配置,開啟降級服務
# 開啟服務降級 feign: hystrix: enabled: true
測試
在訪問該服務時,關閉該服務後,會出現提示
2)服務熔斷與服務降級對比
● 服務熔斷:在服務端處理,某個服務超時或異常,引起熔斷
● 服務降級:在客戶端處理,從整個網站的負載考慮,當某個服務熔斷或者關閉之後,服務將不再被呼叫,此時在客戶端,我們可以準備一個自己的失敗回撥Fallback,返回一個預設值(預設值),整體的服務水平下降了,但是好歹能用,總比直接掛掉要好
四、Dashboard流量監控
新建一個模組 springcloud-consumer-hystrix-dashboard,匯入依賴
<!-- hystrix依賴 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!-- hystrix-dashboard監控 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!-- Ribbon負載均衡 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!-- Eureka服務提供 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!--實體類--> <dependency> <groupId>com.cyan</groupId> <artifactId>springcloud-api</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-devtools</artifactId> </dependency>
application.yaml 配置埠號
server:
port: 9001
建立一個啟動類,並添加註解 @EnableHystrixDashboard,開啟監控
@SpringBootApplication @EnableHystrixDashboard // 開啟監控 public class DeptComsumerDashBoard_9001 { public static void main(String[] args) { SpringApplication.run(DeptComsumerDashBoard_9001.class, args); } }
要保證我們的服務者模組都要有 spring-boot-starter-actuator依賴和 hystrix依賴,來完成監控
<!-- hystrix依賴 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!-- actuator完善eureka監控資訊 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
只啟動該監控服務,訪問 localhost:9001/hystrix
如果想要一個服務被監控,我們需要加一個Bean
在 spirngcloud-provider-dept-8001模組,主啟動類中,新增
@SpringBootApplication @EnableEurekaClient // 在服務啟動後自動註冊到Eureka中 @EnableDiscoveryClient // 服務發現 public class DeptProvider_8001 { public static void main(String[] args) { SpringApplication.run(DeptProvider_8001.class, args); } @Bean public ServletRegistrationBean hystrixMetricsStreamServlet() { ServletRegistrationBean<Servlet> registrationBean = new ServletRegistrationBean<>(new HystrixMetricsStreamServlet()); registrationBean.addUrlMappings("/actuator/hystrix.stream"); return registrationBean; } }
測試
啟動註冊中心,啟動流量監控,啟動該 8001 服務
訪問 localhost:9001/hystrix,將 localhost:8001/actuator/hystrix.stream,新增到監控
會自動跳轉到監控頁面