javascript
Hystrix---SpringCloud
Hystrix
服務熔斷
分布式系統面臨的問題
復雜分布式體系結構中的應用程序有數十個依賴關系,每個依賴關系在某些時候將不可避免失敗!
服務雪崩
多個微服務之間調用的時候,假設微服務A調用微服務B和微服務C,微服務B和微服務C又調用其他的微服務,這就是所謂的“扇出”,如果扇出的鏈路上某個微服務的調用響應時間過長,或者不可用,對微服務A的調用就會占用越來越多的系統資源,進而引起系統崩潰,所謂的“雪崩效應”。
對于高流量的應用來說,單一的后端依賴可能會導致所有服務器上的所有資源都在幾十秒內飽和。比失敗更糟糕的是,這些應用程序還可能導致服務之間的延遲增加,備份隊列,線程和其他系統資源緊張,導致整個系統發生更多的級聯故障,這些都表示需要對故障和延遲進行隔離和管理,以達到單個依賴關系的失敗而不影響整個應用程序或系統運行。
我們需要,棄車保帥!
Hystrix作用
Hystrix是一個應用于處理分布式系統的延遲和容錯的開源庫,在分布式系統里,許多依賴不可避免的會調用失敗,比如超時,異常等,Hystrix 能夠保證在一個依賴出問題的情況下,不會導致整個體系服務失敗,避免級聯故障,以提高分布式系統的彈性。
“斷路器”本身是一種開關裝置,當某個服務單元發生故障之后,通過斷路器的故障監控 (類似熔斷保險絲) ,向調用方返回一個服務預期的,可處理的備選響應 (FallBack) ,而不是長時間的等待或者拋出調用方法無法處理的異常,這樣就可以保證了服務調用方的線程不會被長時間,不必要的占用,從而避免了故障在分布式系統中的蔓延,乃至雪崩。
Hystrix能干嘛?
- 服務降級
- 服務熔斷
- 服務限流
- 接近實時的監控
- …
當一切正常時,請求流可以如下所示:
當許多后端系統中有一個潛在阻塞服務時,它可以阻止整個用戶請求:
隨著大容量通信量的增加,單個后端依賴項的潛在性會導致所有服務器上的所有資源在幾秒鐘內飽和。
應用程序中通過網絡或客戶端庫可能導致網絡請求的每個點都是潛在故障的來源。比失敗更糟糕的是,這些應用程序還可能導致服務之間的延遲增加,從而備份隊列、線程和其他系統資源,從而導致更多跨系統的級聯故障。
當使用Hystrix包裝每個基礎依賴項時,上面的圖表中所示的體系結構會發生類似于以下關系圖的變化。每個依賴項是相互隔離的,限制在延遲發生時它可以填充的資源中,并包含在回退邏輯中,該邏輯決定在依賴項中發生任何類型的故障時要做出什么樣的響應:
官網資料:https://github.com/Netflix/Hystrix/wiki
服務熔斷(服務端)
什么是服務熔斷?
熔斷機制是賭贏雪崩效應的一種微服務鏈路保護機制。
當扇出鏈路的某個微服務不可用或者響應時間太長時,會進行服務的降級,進而熔斷該節點微服務的調用,快速返回錯誤的響應信息。檢測到該節點微服務調用響應正常后恢復調用鏈路。在SpringCloud框架里熔斷機制通過Hystrix實現。Hystrix會監控微服務間調用的狀況,當失敗的調用到一定閥值缺省是5秒內20次調用失敗,就會啟動熔斷機制。熔斷機制的注解是:@HystrixCommand。
服務熔斷解決如下問題:
- 當所依賴的對象不穩定時,能夠起到快速失敗的目的;
- 快速失敗后,能夠根據一定的算法動態試探所依賴對象是否恢復。
案例
新建springcloud-provider-dept-hystrix-8001模塊并拷貝springcloud-provider-dept–8001內的pom.xml、resource和Java代碼進行初始化并調整。
導入hystrix依賴
<!--導入Hystrix依賴--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-hystrix</artifactId><version>1.4.6.RELEASE</version> </dependency>調整yml配置文件
server:port: 8001# mybatis配置 mybatis:# springcloud-api 模塊下的pojo包type-aliases-package: com.haust.springcloud.pojo# 本模塊下的mybatis-config.xml核心配置文件類路徑config-location: classpath:mybatis/mybatis-config.xml# 本模塊下的mapper配置文件類路徑mapper-locations: classpath:mybatis/mapper/*.xml# spring配置 spring:application:#項目名name: springcloud-provider-deptdatasource:# 德魯伊數據源type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8username: rootpassword: root# Eureka配置:配置服務注冊中心地址 eureka:client:service-url:# 注冊中心地址7001-7003defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/instance:instance-id: springcloud-provider-dept-hystrix-8001 #修改Eureka上的默認描述信息prefer-ip-address: true #改為true后默認顯示的是ip地址而不再是localhost#info配置 info:app.name: haust-springcloud #項目的名稱company.name: com.haust #公司的名稱prefer-ip-address: false:
prefer-ip-address: true:
修改controller
/*** @Auther: csp1999* @Date: 2020/05/17/22:06* @Description: 提供Restful服務*/ @RestController public class DeptController {@Autowiredprivate DeptService deptService;/*** 根據id查詢部門信息* 如果根據id查詢出現異常,則走hystrixGet這段備選代碼* @param id* @return*/@HystrixCommand(fallbackMethod = "hystrixGet")@RequestMapping("/dept/get/{id}")//根據id查詢public Dept get(@PathVariable("id") Long id){Dept dept = deptService.queryById(id);if (dept==null){throw new RuntimeException("這個id=>"+id+",不存在該用戶,或信息無法找到~");}return dept;}/*** 根據id查詢備選方案(熔斷)* @param id* @return*/public Dept hystrixGet(@PathVariable("id") Long id){return new Dept().setDeptno(id).setDname("這個id=>"+id+",沒有對應的信息,null---@Hystrix~").setDb_source("在MySQL中沒有這個數據庫");} }為主啟動類添加對熔斷的支持注解@EnableCircuitBreaker
/*** @Auther: csp1999* @Date: 2020/05/17/22:09* @Description: 啟動類*/ @SpringBootApplication @EnableEurekaClient // EnableEurekaClient 客戶端的啟動類,在服務啟動后自動向注冊中心注冊服務 @EnableDiscoveryClient // 服務發現~ @EnableCircuitBreaker // 添加對熔斷的支持注解 public class HystrixDeptProvider_8001 {public static void main(String[] args) {SpringApplication.run(HystrixDeptProvider_8001.class,args);} }測試:
使用熔斷后,當訪問一個不存在的id時,前臺頁展示數據如下:
而不適用熔斷的springcloud-provider-dept–8001模塊訪問相同地址會出現下面狀況:
因此,為了避免因某個微服務后臺出現異常或錯誤而導致整個應用或網頁報錯,使用熔斷是必要的
顯示服務的ip
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-kcig9Ijz-1610712704721)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115162939925.png)]
服務降級(客戶端)
什么是服務降級?
服務降級是指 當服務器壓力劇增的情況下,根據實際業務情況及流量,對一些服務和頁面有策略的不處理,或換種簡單的方式處理,從而釋放服務器資源以保證核心業務正常運作或高效運作。說白了,就是盡可能的把系統資源讓給優先級高的服務。
資源有限,而請求是無限的。如果在并發高峰期,不做服務降級處理,一方面肯定會影響整體服務的性能,嚴重的話可能會導致宕機某些重要的服務不可用。所以,一般在高峰期,為了保證核心功能服務的可用性,都要對某些服務降級處理。比如當雙11活動時,把交易無關的服務統統降級,如查看螞蟻深林,查看歷史訂單等等。
服務降級主要用于什么場景呢?當整個微服務架構整體的負載超出了預設的上限閾值或即將到來的流量預計將會超過預設的閾值時,為了保證重要或基本的服務能正常運行,可以將一些 不重要 或 不緊急 的服務或任務進行服務的 延遲使用 或 暫停使用。
降級的方式可以根據業務來,可以延遲服務,比如延遲給用戶增加積分,只是放到一個緩存中,等服務平穩之后再執行 ;或者在粒度范圍內關閉服務,比如關閉相關文章的推薦。
由上圖可得,當某一時間內服務A的訪問量暴增,而B和C的訪問量較少,為了緩解A服務的壓力,這時候需要B和C暫時關閉一些服務功能,去承擔A的部分服務,從而為A分擔壓力,叫做服務降級。
服務降級需要考慮的問題
- 1)那些服務是核心服務,哪些服務是非核心服務
- 2)那些服務可以支持降級,那些服務不能支持降級,降級策略是什么
- 3)除服務降級之外是否存在更復雜的業務放通場景,策略是什么?
自動降級分類
1)超時降級:主要配置好超時時間和超時重試次數和機制,并使用異步機制探測回復情況
2)失敗次數降級:主要是一些不穩定的api,當失敗調用次數達到一定閥值自動降級,同樣要使用異步機制探測回復情況
3)故障降級:比如要調用的遠程服務掛掉了(網絡故障、DNS故障、http服務返回錯誤的狀態碼、rpc服務拋出異常),則可以直接降級。降級后的處理方案有:默認值(比如庫存服務掛了,返回默認現貨)、兜底數據(比如廣告掛了,返回提前準備好的一些靜態頁面)、緩存(之前暫存的一些緩存數據)
4)限流降級:秒殺或者搶購一些限購商品時,此時可能會因為訪問量太大而導致系統崩潰,此時會使用限流來進行限制訪問量,當達到限流閥值,后續請求會被降級;降級后的處理方案可以是:排隊頁面(將用戶導流到排隊頁面等一會重試)、無貨(直接告知用戶沒貨了)、錯誤頁(如活動太火爆了,稍后重試)。
入門案例
在springcloud-api模塊下的service包中新建降級配置類DeptClientServiceFallBackFactory.java
/*** @Auther: csp1999* @Date: 2020/05/20/9:18* @Description: Hystrix服務降級 ~*/ @Component public class DeptClientServiceFallBackFactory implements FallbackFactory {@Overridepublic DeptClientService create(Throwable cause) {return new DeptClientService() {@Overridepublic Dept queryById(Long id) {return new Dept().setDeptno(id).setDname("id=>" + id + "沒有對應的信息,客戶端提供了降級的信息,這個服務現在已經被關閉").setDb_source("沒有數據~");}@Overridepublic List<Dept> queryAll() {return null;}@Overridepublic Boolean addDept(Dept dept) {return false;}};} }在DeptClientService中指定降級配置類DeptClientServiceFallBackFactory
@Component //注冊到spring容器中 //@FeignClient:微服務客戶端注解,value:指定微服務的名字,這樣就可以使Feign客戶端直接找到對應的微服務 @FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallBackFactory.class)//fallbackFactory指定降級配置類 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模塊中開啟降級:
server:port: 80# Eureka配置 eureka:client:register-with-eureka: false # 不向 Eureka注冊自己service-url: # 從三個注冊中心中隨機取一個去訪問defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/# 開啟降級feign.hystrix feign:hystrix:enabled: true服務熔斷VS降級VS限流
- 服務熔斷—>服務端:某個服務超時或異常,引起熔斷~,類似于保險絲(自我熔斷)
- 服務降級—>客戶端:從整體網站請求負載考慮,當某個服務熔斷或者關閉之后,服務將不再被調用,此時在客戶端,我們可以準備一個 FallBackFactory ,返回一個默認的值(缺省值)。會導致整體的服務下降,但是好歹能用,比直接掛掉強。
- 觸發原因不太一樣,服務熔斷一般是某個服務(下游服務)故障引起,而服務降級一般是從整體負荷考慮;管理目標的層次不太一樣,熔斷其實是一個框架級的處理,每個微服務都需要(無層級之分),而降級一般需要對業務有層級之分(比如降級一般是從最外圍服務開始)
- 實現方式不太一樣,服務降級具有代碼侵入性(由控制器完成/或自動降級),熔斷一般稱為自我熔斷。
熔斷,降級,限流:
限流:限制并發的請求訪問量,超過閾值則拒絕;
降級:服務分優先級,犧牲非核心服務(不可用),保證核心服務穩定;從整體負荷考慮;
熔斷:依賴的下游服務故障觸發熔斷,避免引發本系統崩潰;系統自動執行和恢復
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> <!--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> <!--實體類+web--> <dependency><groupId>com.haust</groupId><artifactId>springcloud-api</artifactId><version>1.0-SNAPSHOT</version> </dependency> <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>主啟動類
@SpringBootApplication // 開啟Dashboard @EnableHystrixDashboard public class DeptConsumerDashboard_9001 {public static void main(String[] args) {SpringApplication.run(DeptConsumerDashboard_9001.class,args);} }給springcloud-provider-dept-hystrix-8001模塊下的主啟動類添加如下代碼,添加監控
@SpringBootApplication @EnableEurekaClient //EnableEurekaClient 客戶端的啟動類,在服務啟動后自動向注冊中心注冊服務 public class DeptProvider_8001 {public static void main(String[] args) {SpringApplication.run(DeptProvider_8001.class,args);}//增加一個 Servlet@Beanpublic ServletRegistrationBean hystrixMetricsStreamServlet(){ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());//訪問該頁面就是監控頁面registrationBean.addUrlMappings("/actuator/hystrix.stream");return registrationBean;} }訪問:http://localhost:9001/hystrix
進入監控頁面:
效果如下圖:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-wEUywKlj-1610712704723)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115190406423.png)]
一些問題解決辦法
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-JzxwAsBy-1610712704725)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115190154045.png)]
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ME07L0Y7-1610712704728)(C:\Users\王東梁\AppData\Roaming\Typora\typora-user-images\image-20210115190205062.png)]
總結
以上是生活随笔為你收集整理的Hystrix---SpringCloud的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 负载均衡Ribbon和Feign---S
- 下一篇: 如何实现多台电脑共享打印机如何使多台电脑