Hystrix熔断器
分布式系统所面临的问题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G9KxR96h-1601736626484)(C:\Users\74551\AppData\Roaming\Typora\typora-user-images\image-20200819164248112.png)]
Hystrix是什么
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免会调用失败,比如超市,异常等,Hysrix能够保证一个依赖出问题得情况下,不会导致整个服务崩溃导致级联故障, 提高分布式系统的弹性
“断路器“本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似保险丝)想调用发返回一个符合预期的,可处理的备用响应(FallBack),而不是长时间的等待或者爆出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间,不必要的占用,从而避免分布式系统中的蔓延,乃至雪崩。
能干嘛
服务降级, 服务熔断, 接近实时的监控
停止更新进入维护
重要概念
服务降级: 服务器忙,不让客户等待立刻返回一个友好提示,fallback
哪些情况会发生服务降级?
程序运行时异常, 超市, 服务熔断触发服务降级, 线程池/信号量也会导致服务降级
服务熔断 类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示 服务降级 -》 服务熔断 -》 恢复调用链路
‘服务限流 秒杀高并发等操作, 严禁一窝蜂的过来太拥挤,大家排队, 一秒N个有序进行
hystrix工作流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dsjsx9kR-1601736626487)(C:\Users\74551\AppData\Roaming\Typora\typora-user-images\image-20200819170520056.png)]
步骤说明
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cRnFEDE1-1601736626490)(C:\Users\74551\AppData\Roaming\Typora\typora-user-images\image-20200819170534673.png)]
Hystrix案例
创建新的Model cloud-provider-hystrix-payment8001
pom文件
<dependencies>
<!--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-server</artifactId>
</dependency>
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-common</artifactId>
<version>${project.version}</version>
</dependency>
<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>
yml文件
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
主启动
@SpringBootApplication
@EnableEurekaClient
public class PaymentHystrixMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentHystrixMain8001.class, args);
}
}
service 和controller省略
在并发量不高的情况下可以支撑服务请求秒回但是并发高了以后就相互影响
使用Jmeter压力测试, 在压力测试下会发现两个服务的请求都会转圈
如果外部消费者80也来访问,那消费者只能干等,导致80消费者不满意最后服务端被8001拖死
新建消费端 cloud-consumer-feign-hystrix-order80
pom
<dependencies>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-common</artifactId>
<version>${project.version}</version>
</dependency>
<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>
yml
server:
port: 80
eureka:
client:
register-with-eureka: false
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
主启动
@SpringBootApplication
@EnableEurekaClient //开启eureka
@EnableFeignClients //开启feign
public class OrderHystrixMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderHystrixMain80.class, args);
}
}
高并发下测试消费者要么转圈要么消费端超时报错
故障和导致的现象 8001同一层次的其他接口被困死, 因为tomact线程池里面的工作线程已经被挤占完毕
80此时调用8001,客户端访问响应缓慢,转圈圈
这时我们的降级容错,限流基础诞生
如何解决?
超时导致服务器变慢–》 超时后不再等待
出错 --》 出错有兜底
解决对方服务(8001)超时了,或者宕机,调用者(80)不能一直卡死,必须有服务降级
解决调用者自己有故障或者自我要求等待时间小于服务提供者
服务降级配置
@HystrixCommand
先从服务端解决问题,设置自身调用
业务类Service
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5GvHiLh4-1601736626494)(C:\Users\74551\AppData\Roaming\Typora\typora-user-images\image-20200819174333333.png)]
上面增加
@HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")
})
//在方法头上加 paymentInfo_TimeOutHandler兜底方法
主启动类上加@EnableCircuitBreaker //回路
服务消费者端解决服务降级
pom
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency
yml
server:
port: 80
eureka:
client:
register-with-eureka: false
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
feign:
hystrix:
enabled: true
主启动@EnableHystrix
业务类Controller
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;
return paymentHystrixService.paymentInfo_TimeOut(id);
}
public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
return "我是消费者80,对方支付系统繁忙请10秒种后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
}
但是这么写的话就会产生2个问题
每个业务方法都对应一个兜底的方法,代码膨胀,统一的和自定义的分开
解决代码膨胀问题
controller层增加注解
@RestController
@Slf4j
@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) {
return paymentHystrixService.paymentInfo_OK(id);
}
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
/*@HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
})*/
@HystrixCommand
public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
//int age = 10/0;
return paymentHystrixService.paymentInfo_TimeOut(id);
}
public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
return "我是消费者80,对方支付系统繁忙请10秒种后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
}
/**
* 全局fallback
*
* @return
*/
public String payment_Global_FallbackMethod() {
return "Global异常处理信息,请稍后重试.o(╥﹏╥)o";
}
}
没有特殊制定回调方法但是增加了@ystrixCommand
则自动默认全局回调方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XmKe8zty-1601736626496)(C:\Users\74551\AppData\Roaming\Typora\typora-user-images\image-20200819175758132.png)]
逻辑混乱解决方法
利用Feign接口在Service接口中增加注解@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT", fallback = PaymentFallbackService.class)
相同包下增加一个实体类PaymentFallbackService继承Service的接口复写fallback方法
服务熔断
断路器 一句话就是家里的保险丝
熔断是什么
熔断机制概述:熔断机制是对应雪崩效应的一种微服务链路保护机制,当扇出链路的某个微服务出错或者不可用享用时间太长时,会进行服务降级,进而熔断该节点微服务调用,快读返回相信信息。当检测到该节点微服务正常后,恢复调用链路
在SpringCloud的框架里,熔断机制通过Hystrix实现,Hystrix会监控微服务间调用的状况。当失败的调用到一定阈值,缺省的5秒内20次失败调用,就会启动熔断机制,注解为@HystrixCommand
修改cloud-provider-hystrix-payment8001
paymentService
// 服务熔断
@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;
}
Controller增加方法测试
//服务熔断
@GetMapping("/payment/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id){
String result = paymentService.paymentCircuitBreaker(id);
log.info("*****result="+result);
return result;
}
结论
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uDEtgqcW-1601736626498)(C:\Users\74551\AppData\Roaming\Typora\typora-user-images\image-20200819182029387.png)]
多次错误然后正确,刚开始就算正确也不能进行访问
熔断类型:
熔断打开: 请求不在调用当前服务,内部设置为一般MTTR(平均故障处理时间)当打开长达到所设置的进入半熔断状态
熔断关闭: 熔断后不会对服务进行熔断
熔断搬开: 部分请求规则调用当前服务,如果请求成功并且符合规则认为当前服务恢复正常,关闭熔断
断路器在什么情况下开始起作用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W7K0OLHh-1601736626499)(C:\Users\74551\AppData\Roaming\Typora\typora-user-images\image-20200819182450029.png)]
断路器开启或者关闭的条件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bRs4H7s0-1601736626500)(C:\Users\74551\AppData\Roaming\Typora\typora-user-images\image-20200819182854124.png)]
断路器打开之后
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UvEQl7Ev-1601736626501)(C:\Users\74551\AppData\Roaming\Typora\typora-user-images\image-20200819182939333.png)]
所有配置断路器
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YGB5463W-1601736626502)(C:\Users\74551\AppData\Roaming\Typora\typora-user-images\image-20200819183059309.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BmuuVFSZ-1601736626503)(C:\Users\74551\AppData\Roaming\Typora\typora-user-images\image-20200819183139158.png)]
服务限流
后面alibaba的Sentinel说明
服务监控HystrixDashboard
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l2mGfPOW-1601736626504)(C:\Users\74551\AppData\Roaming\Typora\typora-user-images\image-20200819183339697.png)]
新建model-consumer-hystrix-dashboar9001
pom
<dependencies>
<!--hystrix dashboard-->
<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>
yml文件
server:
port: 9001
主启动类
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardMain9001 {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardMain9001.class);
}
}
所有的服务提供者需要增加监控依赖
<!--监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
监控地址http://localhost:9001/hystrix
服务和调用者的朱启动类上增加配置,否则会Unable to connect to Command Metric Stream
/**
* 此配置是为了服务监控而配置,与服务容错本身无观,springCloud 升级之后的坑
* ServletRegistrationBean因为springboot的默认路径不是/hystrix.stream
* 只要在自己的项目中配置上下面的servlet即可
* @return
*/
@Bean
public ServletRegistrationBean getServlet(){
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean<HystrixMetricsStreamServlet> registrationBean = new ServletRegistrationBean<>(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
9001监控8001: http//localhost:8001/hystrix.stream
图解监控
七色
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HrCNwzJK-1601736626506)(C:\Users\74551\AppData\Roaming\Typora\typora-user-images\image-20200819184128017.png)]
一圈
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XPteABOf-1601736626507)(C:\Users\74551\AppData\Roaming\Typora\typora-user-images\image-20200819184151903.png)]
一线
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kouKgmnM-1601736626507)(C:\Users\74551\AppData\Roaming\Typora\typora-user-images\image-20200819184207941.png)]
整图说明
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EuHADzFH-1601736626508)(C:\Users\74551\AppData\Roaming\Typora\typora-user-images\image-20200819184227239.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2jGBAiaw-1601736626510)(C:\Users\74551\AppData\Roaming\Typora\typora-user-images\image-20200819184227389.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5GmERxS1-1601736626511)(C:\Users\74551\AppData\Roaming\Typora\typora-user-images\image-20200819184239495.png)]