Hystrix是由Netflix開源的一個針對分佈式系統容錯處理的開源組件。
1)通過客戶端庫對延遲和故障進行保護和控制。(當被訪問的服務或方法失敗時會調用自定義的容錯方法,容錯方法通常都是已日誌和失敗提示爲主,這樣做使得調用發生的錯誤更優雅的表現出來)。
2)在一個複雜的分佈式系統中停止級聯故障。(例如當A服務調用B服務時,此時B服務因爲其他服務的調用壓力過大延遲或奔潰,那麼A根據配置:過期時間,請求數量等配置觸發fallback邏輯“容錯邏輯”)。
3)快速失敗和迅速恢復。(根據請求失敗率來進行自動隔離服務,此時服務會拒絕所有請求,直到內部線程空出來在迅速恢復服務)
4)在合理的情況下回退和優雅地降級。(當請求壓力大時,會將服務降級“只處理當前進程內邏輯不再接收新的請求”)
5)開啓近實時監控、告警和操作控制。(提供鏈路追蹤的儀表盤,供運維/開發推斷當前配置是否合理)。
Hystrix基本操作:
例子一:
1.eureka客戶端,服務端前幾節有
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>cn.springcloud.book</groupId> <artifactId>ch6-1</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>ch6-1-client-service</artifactId> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
bootstrap.yml
server:
port: 8888
spring:
application:
name: sc-client-service
eureka:
client:
serviceUrl:
defaultZone: http://${eureka.host:127.0.0.1}:${eureka.port:8761}/eureka/
instance:
prefer-ip-address: true
ClientApplication:@EnableHystrix啓用Hsystrix
package cn.springcloud.book; 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.hystrix.EnableHystrix; /** * @author www.springcloud.cn * */ @SpringBootApplication @EnableHystrix @EnableDiscoveryClient public class ClientApplication { public static void main(String[] args) { SpringApplication.run(ClientApplication.class, args); } }
IUserService
package cn.springcloud.book.service; public interface IUserService { public String getUser(String username) throws Exception; }
UserService:@HystrixCommand(fallbackMethod="defaultUser"),在此處執行hystrix命令,要是被修飾的方法執行失敗則執行指定的方法“defaultUser”
package cn.springcloud.book.service.impl; import org.springframework.stereotype.Component; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import cn.springcloud.book.service.IUserService; /** */ @Component public class UserService implements IUserService{ @Override @HystrixCommand(fallbackMethod="defaultUser") public String getUser(String username) throws Exception { if(username.equals("spring")) { return "This is real user"; }else { throw new Exception(); } } /** * 出錯則調用該方法返回友好錯誤 * @param username * @return */ public String defaultUser(String username) { return "The user does not exist in this system"; } }
TestController
package cn.springcloud.book.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import cn.springcloud.book.service.IUserService; @RestController public class TestController { @Autowired private IUserService userService; @GetMapping("/getUser") public String getUser(@RequestParam String username) throws Exception{ return userService.getUser(username); } }
然後啓動eureka server後啓動此項目即可訪問controller,可以看到當參數爲:spring時返回getUser方法的:"This is real user",否則返回defaultUser方法的:"The user does not exist in this system"。
這就是hystrix在代碼層展示最直觀的方式。
例子二:
spring cloud feign服務間調用也集成了spring cloud hystrix,以及負載均衡 spring cloud ribbon,當調用別的服務失敗時會觸發fallback指定類對應的方法,fallback指定類藥實現當前當前調用接口。
package cn.springcloud.book; 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.hystrix.EnableHystrix; import org.springframework.cloud.openfeign.EnableFeignClients; /** * @author www.springcloud.cn */ @SpringBootApplication @EnableHystrix @EnableDiscoveryClient @EnableFeignClients public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } }
package cn.springcloud.book.service; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import cn.springcloud.book.service.impl.UserServiceFallback; @FeignClient(name = "sc-provider-service", fallback = UserServiceFallback.class) public interface IUserService { @RequestMapping(value = "/getUser",method = RequestMethod.GET) public String getUser(@RequestParam("username") String username); }
package cn.springcloud.book.service.impl; import org.springframework.stereotype.Component; import cn.springcloud.book.service.IUserService; @Component public class UserServiceFallback implements IUserService{ /** * 出錯則調用該方法返回友好錯誤 * @param username * @return */ public String getUser(String username){ return "The user does not exist in this system, please confirm username"; } }
package cn.springcloud.book.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import cn.springcloud.book.service.IUserService; @RestController public class TestController { @Autowired private IUserService userService; @RequestMapping(value = "/getUser",method = RequestMethod.GET) public String getUser(@RequestParam("username") String username) throws Exception{ return userService.getUser(username); } }
yml配置:記得在spring cloud feign的配置中打開hystrix,否則hystrix不起作用,調用失敗不會測試調用失敗拋出異常後不會優雅的提示,直接會報錯500.
feign:
hystrix:
enabled: true
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>cn.springcloud.book</groupId> <artifactId>ch6-2</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <artifactId>ch6-2-consumer-service</artifactId> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
要訪問服務的controller,要訪問的項目爲一個正常的擁有controller接口的服務。如果知識單純的被訪問在不需要引入hystrix.
package cn.springcloud.book.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @RequestMapping(value = "/getUser",method = RequestMethod.GET) public String getUser(@RequestParam("username") String username) throws Exception{ if(username.equals("spring")) { return "This is real user"; }else { throw new Exception(); } } }
hystrix統計各個服務健康狀況,合併請求,隔離方式:https://weread.qq.com/web/reader/71d32370716443e271df020kd67323c0227d67d8ab4fb04