SpringCloud系列七:Hystrix 熔斷機制(Hystrix基本配置、服務降級、HystrixDashboard服務監控、Turbine聚合監控)
1、概念:Hystrix 熔斷機制
2、具體內容
所謂的熔斷機制和日常生活中見到電路保險絲是非常相似的,當出現了問題之後,保險絲會自動燒斷,以保護我們的電器, 那麽如果換到了程序之中呢?
當現在服務的提供方出現了問題之後整個的程序將出現錯誤的信息顯示,而這個時候如果不想出現這樣的錯誤信息,而希望替換為一個錯誤時的內容。
一個服務掛了後續的服務跟著不能用了,這就是雪崩效應
對於熔斷技術的實現需要考慮以下幾種情況:
· 出現錯誤之後可以 fallback 錯誤的處理信息;
· 如果要結合 Feign 一起使用的時候還需要在 Feign(客戶端)進行熔斷的配置。
2.1、Hystrix 基本配置
1、 【microcloud-provider-dept-hystrix-8001】修改 pom.xml 配置文件,追加 Hystrix 配置類:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency>
2、 【microcloud-provider-dept-hystrix-8001】修改 DeptRest 程序
package cn.study.microcloud.rest; import javax.annotation.Resource; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController;import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import cn.study.microcloud.service.IDeptService; import cn.study.vo.Dept; @RestController public class DeptRest { @Resource private IDeptService deptService; @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET) @HystrixCommand(fallbackMethod="getFallback") // 如果當前調用的get()方法出現了錯誤,則執行fallback public Object get(@PathVariable("id") long id) { Dept vo = this.deptService.get(id) ; // 接收數據庫的查詢結果 if (vo == null) { // 數據不存在,假設讓它拋出個錯誤 throw new RuntimeException("部門信息不存在!") ; } return vo ; } public Object getFallback(@PathVariable("id") long id) { // 此時方法的參數 與get()一致 Dept vo = new Dept() ; vo.setDeptno(999999L); vo.setDname("【ERROR】Microcloud-Dept-Hystrix"); // 錯誤的提示 vo.setLoc("DEPT-Provider"); return vo ; } }
一旦 get()方法上拋出了錯誤的信息,那麽就認為該服務有問題,會默認使用“@HystrixCommand”註解之中配置好的 fallbackMethod 調用類中的指定方法,返回相應數據。
3、 【microcloud-provider-dept-hystrix-8001】在主類之中啟動熔斷處理
package cn.study.microcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient @EnableCircuitBreaker @EnableDiscoveryClient public class Dept_8001_StartSpringCloudApplication { public static void main(String[] args) { SpringApplication.run(Dept_8001_StartSpringCloudApplication.class, args); } }
現在的處理情況是:服務器出現了錯誤(但並不表示提供方關閉),那麽此時會調用指定方法的 fallback 處理。
2.2、服務降級(服務回退)
所有的 RPC 技術裏面服務降級是一個最為重要的話題,所謂的降級指的是當服務的提供方不可使用的時候,程序不會出現異常,而會出現本地的操作調用。
例如:在每年年底 12306 都是最繁忙的時候,那麽在這個情況會發現有一些神奇的情況:當到了指定的時間大家開始搶票的 時候,如果你不搶,而後查詢一些冷門的車次,票有可能查詢不出來。因為這個時候會將所有的系統資源給搶票調度了,而其它的 服務由於其暫時不受到過多的關註,這個時候可以考慮將服務降級(服務暫停)。
服務的降級處理是在客戶端實現的,與你的服務器端沒有關系。
1、 【microcloud-service】擴充一個 IDeptService 的失敗調用(服務降級)處理:
package cn.study.service.fallback; import java.util.List; import org.springframework.stereotype.Component; import cn.study.service.IDeptClientService; import cn.study.vo.Dept; import feign.hystrix.FallbackFactory; @Component public class IDeptClientServiceFallbackFactory implements FallbackFactory<IDeptClientService> { @Override public IDeptClientService create(Throwable cause) { return new IDeptClientService() { @Override public Dept get(long id) { Dept vo = new Dept(); vo.setDeptno(888888L); vo.setDname("【ERROR】Feign-Hystrix"); // 錯誤的提示 vo.setLoc("Consumer客戶端提供"); return vo; } @Override public List<Dept> list() { return null; } @Override public boolean add(Dept dept) { return false; } }; } }
2、 【microcloud-service】修改 IDeptClientService 接口,追加本地的 Fallback 配置。
package cn.study.service; import java.util.List; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import cn.study.commons.config.FeignClientConfig; import cn.study.service.fallback.IDeptClientServiceFallbackFactory; import cn.study.vo.Dept; @FeignClient(value = "MICROCLOUD-PROVIDER-DEPT", configuration = FeignClientConfig.class, fallbackFactory = IDeptClientServiceFallbackFactory.class) public interface IDeptClientService { @RequestMapping(method = RequestMethod.GET, value = "/dept/get/{id}") public Dept get(@PathVariable("id") long id); @RequestMapping(method = RequestMethod.GET, value = "/dept/list") public List<Dept> list(); @RequestMapping(method = RequestMethod.POST, value = "/dept/add") public boolean add(Dept dept); }
此時當服務不可用的時候就會執行“IDeptClientServiceFallbackFactory”類中返回的 IDeptClientService 接口的匿名對象信息。
3、 【microcloud-consumer-hystrix】修改 application.yml 配置文件,追加 feign 配置啟用。
feign: hystrix: enabled: true
4、 【microcloud-consumer-hystrix】修改程序啟動主類:
package cn.study.microcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.feign.EnableFeignClients; import org.springframework.context.annotation.ComponentScan; @SpringBootApplication @EnableEurekaClient @ComponentScan("cn.study.service,cn.study.microcloud") @EnableFeignClients(basePackages={"cn.study.service"}) public class Consumer_80_StartSpringCloudApplication { public static void main(String[] args) { SpringApplication.run(Consumer_80_StartSpringCloudApplication.class, args); } }
當追加上了“@ComponentScan("cn.mldn.service")”註解之後才可以進行包的掃描配置。
此時即使服務端無法繼續提供服務了,由於存在有服務降級機制,也會保證服務不可用時可以得到一些固定的提示信息。
2.3、HystrixDashboard服務監控
在 Hystrix 裏面提供有一種監控的功能,那麽這個功能就是“Hystrix Dashboard”,可以利用它來進行整體微服務的監控操作。
1、 首先為了方便監控,將建立一個新的監控項目:microcloud-consumer-hystrix-dashboard;
2、 【microcloud-consumer-hystrix-dashboard】修改項目中的 pom.xml 配置文件:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> </dependency>
3、 【microcloud-provider-*】所有的服務提供者之中都一定要提供有監控服務依賴庫:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
4、 【microcloud-consumer-hystrix-dashboard】修改 application.yml 配置文件,主要進行端口的配置:
server:
port: 9001
5、 【microcloud-consumer-hystrix-dashboard】創建一個監控的主類:
package cn.study.microcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; @SpringBootApplication @EnableHystrixDashboard public class HystrixDashboardApplication_9001 { public static void main(String[] args) { SpringApplication.run(HystrixDashboardApplication_9001.class, args); } }
6、 修改 hosts 主機文件,增加主機列表:
127.0.0.1 dashboard.com
服務運行地址:http://dashboard.com:9001/hystrix;
7、 得到 microcloud-provider-dept 的監控信息:http://studyjava:[email protected]:8001/hystrix.stream;
· 如果此時要想獲取監控信息必須去運行微服務;
8、 將之前的監控的路徑http://studyjava:[email protected]:8001/hystrix.stream填寫到之前啟動好的 dashboard 程序頁面之中;
監控效果如下圖所示:
2.4、Turbine 聚合監控
HystrixDashboard 主要的功能是可以針對於某一項微服務進行監控,但是如果說現在有許多的微服務需要進行整體的監控,那 麽這種情況下就可以利用 turbine 技術來實現。
1、 下面準備出一個新的微服務:Company,這個微服務不打算使用 SpringSecurity 安全處理以及 Mybatis 數據庫連接,只是做一 個簡單的數據信息。通過一個已有的 microcloud-provider-hystrix-8001 復制一個新的項目:microcloud-provider-company-8101;
2、 【microcloud-provider-company-8101】修改項目中的 pom.xml 配置文件,將與安全有關的依賴包刪除掉以及與數據庫連接池、MyBatis 的相關的程序類或接口全部刪除掉,只保留有用的包;
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency> <groupId>cn.study</groupId> <artifactId>microcloud-api</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>springloaded</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies>
3、 【microcloud-api】追加一個新的 VO 類:Company。
package cn.study.vo; import java.io.Serializable; @SuppressWarnings("serial") public class Company implements Serializable { private String title ; private String note ; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getNote() { return note; } public void setNote(String note) { this.note = note; } @Override public String toString() { return "Company [title=" + title + ", note=" + note + "]"; } }
4、 【microcloud-provider-company-8101】建立一個新的微服務的程序類:CompanyRest
package cn.study.microcloud.rest; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import cn.study.vo.Company; @RestController public class CompanyRest { @RequestMapping(value = "/company/get/{title}", method = RequestMethod.GET) @HystrixCommand // 如果需要進行性能監控,那麽必須要有此註解 public Object get(@PathVariable("title") String title) { Company vo = new Company() ; vo.setTitle(title); vo.setNote("www.study.cn"); return vo ; } }
5、 【microcloud-provider-company-8101】修改程序的啟動主類:
package cn.study.microcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient @EnableCircuitBreaker @EnableDiscoveryClient public class Company_8101_StartSpringCloudApplication { public static void main(String[] args) { SpringApplication.run(Company_8101_StartSpringCloudApplication.class, args); } }
6、 【microcloud-provider-company-8101】修改 application.yml 配置文件:
server:
port: 8101
eureka:
client: # 客戶端進行Eureka註冊的配置
service-url:
defaultZone: http://edmin:[email protected]:7001/eureka,http://edmin:[email protected]:7002/eureka,http://edmin:[email protected]:7003/eureka
instance:
lease-renewal-interval-in-seconds: 2 # 設置心跳的時間間隔(默認是30秒)
lease-expiration-duration-in-seconds: 5 # 如果現在超過了5秒的間隔(默認是90秒)
instance-id: dept-8001.com # 在信息列表時顯示主機名稱
prefer-ip-address: true # 訪問的路徑變為IP地址
info:
app.name: study-microcloud
company.name: www.study.cn
build.artifactId: $project.artifactId$
build.version: $project.verson$
spring:
application:
name: microcloud-provider-company
7、 【microcloud-provider-company-8101】啟動微服務,隨後取得監控信息:
· 在 hosts 配置文件之中追加有一個映射路徑:
127.0.0.1 company-8101.com
· 訪問地址:http://company-8101.com:8101/company/get/hello;
· hystrix 監控地址:http://company-8101.com:8101/hystrix.stream;
8、 如 果 要 想 實 現 trubine 的 配 置 , 則需要建立一個 turbine項目模塊 , 這個項目可以直接通過之前的 microcloud-consumer-hystrix-dashboard 模塊進行復制為“microcloud-consumer-turbine”模塊;
9、 【microcloud-consumer-turbine】修改 pom.xml 配置文件,追加 turbine 的依賴程序包:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-turbine</artifactId> </dependency>
10、 【microcloud-consumer-turbine】修改 application.yml 配置文件:
server:
port: 9101 # turbine的監聽端口為9101
eureka:
client: # 客戶端進行Eureka註冊的配置
service-url:
defaultZone: http://edmin:[email protected]:7001/eureka,http://edmin:[email protected]:7002/eureka,http://edmin:[email protected]:7003/eureka
instance:
lease-renewal-interval-in-seconds: 2 # 設置心跳的時間間隔(默認是30秒)
lease-expiration-duration-in-seconds: 5 # 如果現在超過了5秒的間隔(默認是90秒)
instance-id: dept-8001.com # 在信息列表時顯示主機名稱
prefer-ip-address: true # 訪問的路徑變為IP地址
turbine:
app-config: MICROCLOUD-PROVIDER-COMPANY,MICROCLOUD-PROVIDER-DEPT # 定義所有要監控的微服務信息
cluster-name-expression: new String("default") # 設置監控的表達式,通過此表達式表示要獲取監控信息名稱
11、 【microcloud-consumer-turbine】建立一個 turbine 的使用主類信息
package cn.study.microcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; import org.springframework.cloud.netflix.turbine.EnableTurbine; @SpringBootApplication @EnableHystrixDashboard @EnableTurbine public class TurbineApplication_9101 { public static void main(String[] args) { SpringApplication.run(TurbineApplication_9101.class, args); } }
12、 【microcloud-consumer-hystrix-dashboard】運行 hystrix-dashboard 監控程序;
13、 【microcloud-consumer-turbine】運行 trubine 聚合監控程序;
· 但是在正常啟動 trubine 的時候出現了以下的錯誤提示信息,這是因為沒有對有安全認證的微服務MICROCLOUD-PROVIDER-DEPT進行安全認證
· 修改 hosts 配置文件,追加一個映射路徑:
127.0.0.1 turbine.com
· trubine 訪問路徑:http://turbine.com:9101/turbine.stream
14、 運行 HystrixDashboard 監控程序:http://dashboard.com:9001/hystrix.stream;
· 在監控的位置上填寫之前設置好的 turbine 的訪問地址看到的效果如下:
15、 【microcloud-security】如果現在需要 turbine 進行加密的微服務的訪問操作,只能夠采取一種折衷方案,就是要去修改整個項目中的安全策略,追加 WEB 安全策略配置:
package cn.study.microcloud.config; import javax.annotation.Resource; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/hystrix.stream","/turbine.stream") ; } @Resource public void configGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("studyjava").password("hello") .roles("USER").and().withUser("admin").password("hello") .roles("USER", "ADMIN"); } @Override protected void configure(HttpSecurity http) throws Exception { // 表示所有的訪問都必須進行認證處理後才可以正常進行 http.httpBasic().and().authorizeRequests().anyRequest() .fullyAuthenticated(); // 所有的Rest服務一定要設置為無狀態,以提升操作性能 http.sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); } }
現在所有的安全策略會自動拋開以上的兩個訪問路徑,這種是基於 Bean 配置,如果要是你現在基於的是 application.yml 文件的配置,則就必須修改 application.yml 配置文件,追加如下內容:
security: ignored: - /hystrix.stream - /turbine.stream
這個時候如果啟動之後沒有出現任何的錯誤提示,那麽就表示現在已經可以繞過了 Security 的配置而直接進行服務的訪問了。
SpringCloud系列七:Hystrix 熔斷機制(Hystrix基本配置、服務降級、HystrixDashboard服務監控、Turbine聚合監控)