SpringCloud --- 服务降级 ( Hystrix熔断器 )
Posted 黑桃️
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud --- 服务降级 ( Hystrix熔断器 )相关的知识,希望对你有一定的参考价值。
服务降级
Hystrix熔断器
🔺 概述
(1) 分布式系统面临的问题
复杂分布式体系结构中的应用程序 有数10个依赖关系,每个依赖关系在某些时候将不可避免地失败
(2) 是什么
(3) 能干嘛
- 服务降级
- 服务熔断
- 接近实时的监控
(4) 官网资料
https://github.com/Netflix/hystrix/wiki
(5) Hystrix官宣,停更进维
- 被动修复bugs
- 不再接受合并请求
- 不再发布新版本
🔺 HyStrix重要概念
(1) 服务降级
服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示,fallback
产生的原因
- 程序运行异常
- 超时
- 服务熔断触发服务降级
- 线程池/信号量也会导致服务降级
(2) 服务熔断
类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示
服务的降级 -> 进而熔断 -> 恢复调用链路
(3) 服务限流
秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行
🔺 hystrix案例
(1) 构建
① 新建模块 cloud-provider-hystrix-payment8001
② 配置 pom.xml
<?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>cloud2020</artifactId>
<groupId>com.atguigu.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-provider-hystrix-payment8001</artifactId>
<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>
</project>
③ 配置 application.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:PaymentService
@Service
public class PaymentService {
// 正常访问
public String paymentInfo_OK(Integer id) {
return "线程池:" + Thread.currentThread().getName() + " paymentInfo_OK,id:" + id + "\\t" + "O(∩_∩)O哈哈~";
}
// 超时访问
public String paymentInfo_TimeOut(Integer id) {
int timeNumber = 3;
try {
// 暂停3秒钟
TimeUnit.SECONDS.sleep(timeNumber);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "线程池:" + Thread.currentThread().getName() + " paymentInfo_TimeOut,id:" + id + "\\t" + "O(∩_∩)O哈哈~ 耗时(秒)" + timeNumber;
}
}
⑥ Controller:PaymentController
@RestController
@Slf4j
public class PaymentController {
@Resource
private PaymentService paymentService;
@GetMapping("/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id) {
String result = paymentService.paymentInfo_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;
}
}
⑦ 测试
以上述为根基平台,从正确->错误->降级熔断->恢复
(2) 高并发测试
① Jmeter压测测试
② Jmeter压测结论
上面还只是服务提供者8001自己测试,假如此时外部的消费者80也来访问,那消费者只能干等,最终导致消费端80不满意,服务端8001直接被拖s
③ 看热闹不嫌弃事大,80新建加入
新建模块 cloud-consumer-feign-hystrix-order80
配置 pom.xml
<?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>cloud2020</artifactId>
<groupId>com.atguigu.springcloud</groupId>
<version>1.0-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>
<!--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>
</project>
配置 application.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
@EnableFeignClients
public class OrderHystrixMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderHystrixMain80.class, args);
}
}
Service:PaymentHystrixService
@Component
@FeignClient("CLOUD-PROVIDER-HYSTRIX-PAYMENT")
public interface PaymentHystrixService {
@GetMapping("/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id) ;
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_TimeOut(@PathVariable("id") Integer id) ;
}
Controller:OrderHyrixController
@RestController
@Slf4j
public class OrderHyrixController {
@Resource
private PaymentHystrixService paymentHystrixService;
@GetMapping("/payment/hystrix/ok/{id}")
public String paymentInfo_OK(@PathVariable("id") Integer id) {
return paymentHystrixService.paymentInfo_OK(id);
}
@GetMapping("/payment/hystrix/timeout/{id}")
public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
return paymentHystrixService.paymentInfo_TimeOut(id);
}
}
正常测试
高并发测试
服务端自测 8001时 200x100 调用,客户端通过 feign也是 200x100,相当于2万个线程去并发访问 8001
(3) 故障和导致现象
8001同一层次的其他接口被困死,因为tomcat线程池里面的工作线程已经被挤占完毕
80此时调用8001,客户端访问响应缓慢,转圈圈
(4) 上述结论
正因为有上述故障或不佳表现 才有我们的降级/容错/限流等技术诞生
(5) 如何解决?解决的要求
- 超时导致服务器变慢(转圈) — 超时不再等待
- 出错(宕机或程序运行出错) — 出错要有兜底
解决
- 对方服务(8001)超时了,调用者(80)不能一直卡死等待,必须有服务降级
- 对方服务(8001)down机了,调用者(80)不能一直卡死等待,必须有服务降级
- 对方服务(8001)ok,调用者(80)自己有故障或有自我要求(自己的等待时间小于服务提供者)
(6) 服务降级
① 降级配置
@HystrixCommand
② 8001 先从自身找问题
设置自身调用超时时间的峰值,峰值内可以正常运行, 超过了需要有兜底的方法处理,做服务降级fallback
③ 8001 fallback
主启动类加上注解才能生效:@EnableCircuitBreaker
对业务类 PaymentService 做些修改
// 超时访问
@HystrixCommand(fallbackMethod = "payment_TimeOutHandler",commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value="3000")
})
public String paymentInfo_TimeOut(Integer id) {
int timeNumber = 13;
try {
// 暂停3秒钟
TimeUnit.SECONDS.sleep(timeNumber);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "线程池:" + Thread.currentThread().getName() + " paymentInfo_TimeOut,id:" + id + "\\t" + "O(∩_∩)O哈哈~ 耗时(秒)" + timeNumber;
}
// 兜底的方案,paymentInfo_TimeOut出现超时或者异常的时候就会调用这个方法
public String payment_TimeOutHandler(Integer id) {
return "/(ToT)/" + "调用支付接口超时或异常:\\t" + "\\t当前线程池名字" + Thread.currentThread().getName();
}
④ 80 fallback
在 pom.xml 加入依赖:
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
什么是服务降级?springCloud如何实现?
4.SpringCloud -- 服务降级熔断 HystrixSentinel
SpringCloud--服务降级--Hystrix之服务降级支付