微服务 SpringCloud Hystrix熔断器
1. Hystrix概述
1.1 Hystrix简介
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时,异常等。
Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
断路器本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控,向调用方返回一个符合预期的。可处理的备选响应,而不是长时间的等待或者抛出调用方法处理异常,这样就保证了服务调用方的线程不会被长时间,不必要的占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
1.2 Hystrix使用场景
服务的限流,熔断,降级
近实时监控
接口隔离
… …
1.3 Hystrix官网资料
官网地址:https://github.com/Netflix/Hystrix
2. Hystrix术语
2.1 服务降级
服务降级就是当服务不可用或者出现问题的时候设置的一个备选方案,不至于是调用者长时间等待,线程长时间不释放时避免服务器宕机,引起级联故障,导致整个服务不可用。
常提示,服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好的提示。
常见降级的情况:
1.程序运行异常
2.超时
3.服务器熔断触发服务降级
4.线程池,信号量打满也会导致服务降级。
2.2 服务熔断
服务熔断就是达到最大服务访问量时,直接拒绝服务,然后调用服务降级方法并返回友好提示,也是避免服务器宕机,引起级联故障,导致整个服务不可用。
2.3 服务限流
服务限流就是达到最大服务请求时限制请求数量,直接拒绝服务,也是避免服务器宕机,引起级联故障,导致整个服务不可用。
3. hystrix案例
hystrix git地址:https://github.com/zrj-coder/cloudboot3
hystrix所有配置信息类
/**
* hystrix所有配置信息都在这个类
*/
public abstract class HystrixCommandProperties {}
3.1 服务降级
hystrix既可以在客户端做限流熔断降级,也可以在服务端做,一般在客户端处理。
无论在客户端还是服务端实现方式都是一样的,这里只做客户端处理。
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>cloudboot3</artifactId>
<groupId>com.hello.springcloud</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-consumer-feign-hystrix-order80</artifactId>
<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.hello.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</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>
<!--一般基础通用配置-->
<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>
</project>
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
feign:
hystrix:
enabled: true
/**
* @author zrj
* @date 2021/1/31
* @since V1.0
**/
@EnableHystrix
@EnableFeignClients
@SpringBootApplication
public class OrderHystrixApplication80 {
public static void main(String[] args) {
SpringApplication.run( OrderHystrixApplication80.class, args );
}
}
/**
* 通过FeignClient调用注册到uereka上的服务:CLOUD-PROVIDER-HYSTRIX-PAYMENT
*
* @author zrj
* @date 2021/1/31
* @since V1.0
**/
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT", fallback = PaymentFallbackService.class)
public interface PaymentHystrixService {
/**
* 服务正常
*/
@GetMapping("/payment/hystrix/ok/{id}")
String paymentInfo_OK(@PathVariable("id") Integer id);
/**
* 服务降级
*/
@GetMapping("/payment/hystrix/timeout/{id}")
String paymentInfo_TimeOut(@PathVariable("id") Integer id);
}
/**
* service降级处理类
*
* @author zrj
* @date 2021/1/31
* @since V1.0
**/
@Component
public class PaymentFallbackService implements PaymentHystrixService {
/**
* 服务正常
*/
@Override
public String paymentInfo_OK(Integer id) {
return "【服务降级】-----PaymentFallbackService fall back-paymentInfo_OK ,o(╥﹏╥)o";
}
/**
* 服务降级
*/
@Override
public String paymentInfo_TimeOut(Integer id) {
return "【服务降级】-----PaymentFallbackService fall back-paymentInfo_TimeOut ,o(╥﹏╥)o";
}
}
/**
* controller降级处理
*
* @author zrj
* @date 2021/1/31
* @since V1.0
**/
@Slf4j
@RestController
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public class OrderHystrixController {
@Resource
private PaymentHystrixService paymentHystrixService;
@GetMapping("/consumer/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id) {
String result = paymentHystrixService.paymentInfo_OK( id );
return result;
}
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
@HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod"
, commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")})
public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
int age = 10 / 0;
String result = paymentHystrixService.paymentInfo_TimeOut( id );
return result;
}
/**
* 只要上述服务不可用,无论是异常或者超时都会走设置的fallbackMethod
*/
public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
return "【服务降级】我是消费者80,对方支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
}
/**
* 全局服务降级
*/
@GetMapping("/consumer/payment/hystrix/timeoutglobal/{id}")
@HystrixCommand
public String paymentInfo_TimeOutGlobal(@PathVariable("id") Integer id) {
int age = 10 / 0;
String result = paymentHystrixService.paymentInfo_TimeOut( id );
return result;
}
/**
* 下面是全局fallback方法
*/
public String payment_Global_FallbackMethod() {
return "【全局fallback】Global异常处理信息,请稍后再试,/(ㄒoㄒ)/~~";
}
}
3.2 服务熔断
大神论文:https://martinfowler.com/bliki/CircuitBreaker.html
断路器三种状态
断路器触发条件
断路器开启或者关闭的条件断路器打开之后
pom文件与上边服务降级一样,不在重复。
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
/**
* @author zrj
* @date 2021/1/31
* @since V1.0
**/
@EnableCircuitBreaker
@EnableEurekaClient
@SpringBootApplication
public class PaymentHystrixApplication8001 {
public static void main(String[] args) {
SpringApplication.run( PaymentHystrixApplication8001.class, args );
}
}
/**
* 服务熔断限流降级接口
*
* @author zrj
* @date 2021/1/31
* @since V1.0
**/
@Service
public class PaymentService {
/**
* 服务正常
*/
public String paymentInto_OK(Integer id) {
return "线程池:" + Thread.currentThread().getName() + " paymentInfo_OK, id: " + id + "\t" + "O(∩_∩)O哈哈~";
}
/**
* 服务超时
*/
@HystrixCommand(fallbackMethod = "paymnetInfo_TimeOutHandler",
commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")})
public String paymentInfo_TimeOut(Integer id) {
//int age = 10/0;
try {
TimeUnit.MILLISECONDS.sleep( 3000 );
} catch (InterruptedException e) {
e.printStackTrace();
}
return "【服务超时】线程池: " + Thread.currentThread().getName() + " id: " + id + "\t" + "O(∩_∩)O哈哈~" + " 耗时(秒): ";
}
/**
* 服务降级
*/
public String paymnetInfo_TimeOutHandler(Integer id) {
return "【服务降级】线程池: " + Thread.currentThread().getName() + " 8001系统繁忙或者运行报错,请稍后再试,id: " + id + "\t" + "o(╥﹏╥)o";
}
/**
* 服务熔断
* 10s时间内,调用10次,失败率达到60%,就会熔断
*/
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback", commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"),// 是否开启断路器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),// 请求次数
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), // 时间窗口期
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"),// 失败率达到多少后跳闸
})
public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
if (id < 0) {
throw new RuntimeException( "******id 不能负数" );
}
String serialNumber = IdUtil.simpleUUID();
return Thread.currentThread().getName() + "\t" + "调用成功,流水号: " + serialNumber;
}
public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id) {
return "【服务降级】id 不能负数,请稍后再试,/(ㄒoㄒ)/~~ id: " + id;
}
}
/**
* @author zrj
* @date 2021/1/31
* @since V1.0
**/
@Slf4j
@RestController
public class PaymentController {
@Resource
private PaymentService paymentService;
@Value("${server.port}")
private String serverPort;
/**
* 服务正常
*/
@GetMapping("/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id) {
String result = paymentService.paymentInto_OK( id );
log.info( "【服务正常】result:" + result );
return result;
}
/**
* 服务降级
*/
@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;
}
/**
* 服务熔断
*/
@GetMapping("/payment/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
String result = paymentService.paymentCircuitBreaker( id );
log.info( "【服务熔断】result: " + result );
return result;
}
}
4. hystrix工作流程
官网地址:https://github.com/Netflix/Hystrix/wiki/How-it-Works
5. hystrix 服务监控
5.1 启动HystrixDashboard
HystrixDashboardMain9001+新注解@EnableHystrixDashboard
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>cloudboot3</artifactId>
<groupId>com.hello.springcloud</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-consumer-hystrix-dashboard9001</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</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>
</project>
server:
port: 9001
/**
* @author zrj
* @date 2021/1/31
* @since V1.0
**/
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardMain9001 {
public static void main(String[] args) {
SpringApplication.run( HystrixDashboardMain9001.class, args );
}
}
5.2 配置HystrixDashboard
- mvn依赖
图形化监控标配
- 配置主程序类
- hystrix 9001监控8001