作用
1、服务降级
触发情况:程序运行异常、超时、服务熔断触发服务降级、线程池/信号量打满也会触发服务降级
2、服务熔断
直接拒绝访问,即使有正确的访问也会短路
3、服务限流
排队有序进行
构建服务
1、建module
provider-hystrix-payment8001
2、改pom
<?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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</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>
3、 配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
defaultZone: http://eureka7001.com:7001/eureka
4、主启动
@SpringBootApplication
@EnableEurekaClient
//注解开启断路器功能
@EnableCircuitBreaker
public class CloudProviderHystrixPayment8001Application {
public static void main(String[] args) {
SpringApplication.run(CloudProviderHystrixPayment8001Application.class, args);
System.out.println("启动成功");
}
}
5、service
@Service
public class PaymentService {
/**
* 正常访问,肯定OK
*
* @param id
* @return
*/
public String paymentInfoOK(Integer id) {
return "线程池: " + Thread.currentThread().getName() + " paymentInfoOK,id: " + id + "\t"
+ "O(∩_∩)O哈哈~";
}
/**
* 超时访问,设置自身调用超时的峰值,峰值内正常运行,超过了峰值需要服务降级 自动调用fallbackMethod 指定的方法
* 超时异常或者运行异常 都会进行服务降级
*
* @param id
* @return
*/
@HystrixCommand(fallbackMethod = "paymentInfoTimeOutHandler", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")
})
public String paymentInfoTimeOut(Integer id) {
// int age = 10/0;
int second = 3;
long start = System.currentTimeMillis();
try {
TimeUnit.SECONDS.sleep(second);
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println(end - start);
return "线程池: " + Thread.currentThread().getName() + " paymentInfoTimeOut,id: " + id + "\t"
+ "O(∩_∩)O哈哈~" + " 耗时(秒): " + second;
}
}
6、controller
@RestController
@RequestMapping("payment")
@Slf4j
public class PaymentController {
/**
* 服务对象
*/
@Resource
private PaymentService paymentService;
@Value("${server.port}")
private String serverPort;
/**
* 正常访问
*
* @param id
* @return
*/
@GetMapping("/hystrix/ok/{id}")
public String paymentInfoOK(@PathVariable("id") Integer id) {
String result = paymentService.paymentInfoOK(id);
log.info("result: " + result);
return result;
}
/**
* 超时或者异常
*
* @param id
* @return
*/
@GetMapping("/hystrix/timeout/{id}")
public String paymentInfoTimeOut(@PathVariable("id") Integer id) {
String result = paymentService.paymentInfoTimeOut(id);
log.info("result: " + result);
return result;
}
}
7、测试
正常访问:http://localhost:8001/payment/hystrix/ok/31
5s返回:http://localhost:8001/payment/hystrix/timeout/31
高并发测试
1、jmeter压力测试
开启Jmeter,来20000个并发压死8001,20000个请求都去访问paymentInfo_TimeOut服务
2、访问上面的测试地址发现两个地址都加载不出或者卡死:tomcat默认的工作线程满了,没有多余的线程来来处理访问
3、加入order服务来调用payment生产者接口
4、建module
cloud-consumer-hystrix-order80
5、改pom
<?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>
<!--新增hystrix-->
<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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</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>
6、配yml
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
7、主启动
@SpringBootApplication
@EnableFeignClients // 启动 feign
@EnableHystrix // 启动 hystrix
public class CloudConsumerFeignHystrixOrder80Application {
public static void main(String[] args) {
SpringApplication.run(CloudConsumerFeignHystrixOrder80Application.class, args);
System.out.println("启动成功");
}
}
8、service
@Component
// FeignFallback 客户端的服务降级 针对 CLOUD-PROVIDER-HYSTRIX-PAYMENT 该服务 提供了一个 对应的服务降级类
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT", fallback = PaymentFallbackServiceImpl.class)
//@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT")
public interface PaymentHystrixService {
@GetMapping("/payment/hystrix/ok/{id}")
String paymentInfoOK(@PathVariable("id") Integer id);
@GetMapping("/payment/hystrix/timeout/{id}")
String paymentInfoTimeOut(@PathVariable("id") Integer id);
}
9、controller
@RestController
@RequestMapping("consumer")
@Slf4j
public class OrderHystrixController {
@Resource
private PaymentHystrixService paymentHystrixService;
@GetMapping("/payment/hystrix/ok/{id}")
public String paymentInfoOK(@PathVariable("id") Integer id) {
String result = paymentHystrixService.paymentInfoOK(id);
return result;
}
@GetMapping("/payment/hystrix/timeout/{id}")
// @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
// @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")
// })
@HystrixCommand
public String paymentInfoTimeOut(@PathVariable("id") Integer id) {
int age = 10 / 0;
String result = paymentHystrixService.paymentInfoTimeOut(id);
return result;
}
}
10、测试
http://localhost/consumer/payment/hystrix/ok/31
11、高并发测试
2w个线程压8001,发现order服务访问一直转圈,或者报超时错误
结论:我们需要有降级、熔断、限流等策略解决问题
8001服务端自身调用fallback
1、主启动修改
@EnableCircuitBreaker
2、接口注解添加
@HystrixCommand(fallbackMethod = "paymentInfoTimeOutHandler", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")
})
3、添加fallback方法
/**
* paymentInfoTimeOut 方法失败后 自动调用此方法 实现服务降级 告知调用者 paymentInfoTimeOut 目前无法正常调用
*
* @param id
* @return
*/
public String paymentInfoTimeOutHandler(Integer id) {
return "线程池: " + Thread.currentThread().getName() + " paymentInfoTimeOutHandler8001系统繁忙或者运行报错,请稍后再试,id: " + id + "\t"
+ "o(╥﹏╥)o";
}
4、测试
order80端fallback
1、修改yml
feign:
hystrix:
enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样。
2、修改主启动
@EnableHystrix
3、业务类
@HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")
4、测试
问题
1、每个业务接口都需要有一个兜底的fallback方法,代码膨胀
2、统一的fallback方法如何和自定义的fallback方法分开
解决问题
1、 controller添加统一的fallback
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")// hystrix 全局fallback方法
2、为接口方法进行统一的异常处理
PaymentFallbackService类实现PaymentFeignClientService接口
@Component
public class PaymentFallbackServiceImpl implements PaymentHystrixService {
@Override
public String paymentInfoOK(Integer id) {
return "-----PaymentFallbackService fall back-paymentInfo_OK ,o(╥﹏╥)o";
}
@Override
public String paymentInfoTimeOut(Integer id) {
return "-----PaymentFallbackService fall back-paymentInfo_TimeOut ,o(╥﹏╥)o";
}
}
3、修改yml
feign:
hystrix:
enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样。
4、修改PaymentHystrixService接口,添加统一的fallback
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT", fallback = PaymentFallbackServiceImpl.class)
5、 测试
1、正常访问:http://localhost/consumer/payment/hystrix/ok/31
2、异常访问:关闭provider,访问降级
服务熔断
是什么
熔断机制是一种应对雪崩效应的微服务链路保护机制
实操
1、修改provider-hystrix-payment8001
/**
* 服务熔断 超时、异常、都会触发熔断
* 1、默认是最近10秒内收到不小于10个请求,<br/>
* 2、并且有60%是失败的<br/>
* 3、就开启断路器<br/>
* 4、开启后所有请求不再转发,降级逻辑自动切换为主逻辑,减小调用方的响应时间<br/>
* 5、经过一段时间(时间窗口期,默认是5秒),断路器变为半开状态,会让其中一个请求进行转发。<br/>
* 5.1、如果成功,断路器会关闭,<br/>
* 5.2、若失败,继续开启。重复4和5<br/>
*
* @param id
* @return
*/
@HystrixCommand(fallbackMethod = "paymentCircuitBreakerFallback", 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"),// 失败率达到多少后跳闸
// @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")// 超时处理
})
public String paymentCircuitBreaker(Integer id) {
if (id < 0) {
throw new RuntimeException("******id 不能负数");
}
//测试异常
// int age = 10 / 0;
// int second = 3;
// try {
// TimeUnit.SECONDS.sleep(second);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
String serialNumber = IdUtil.simpleUUID();
return Thread.currentThread().getName() + "\t" + "调用成功,流水号: " + serialNumber;
}
/**
* paymentCircuitBreaker 方法的 fallback,<br/>
* 当断路器开启时,主逻辑熔断降级,该 fallback 方法就会替换原 paymentCircuitBreaker 方法,处理请求
*
* @param id
* @return
*/
public String paymentCircuitBreakerFallback(Integer id) {
return Thread.currentThread().getName() + "\t" + "id 不能负数或超时或自身错误,请稍后再试,/(ㄒoㄒ)/~~ id: " + id;
}
2、修改paymentController
/**
* 服务熔断
*
* @param id
* @return
*/
@GetMapping("/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
String result = paymentService.paymentCircuitBreaker(id);
log.info("****result: " + result);
return result;
}
3、测试
正确:http://localhost:8001/payment/circuit/31
错误:http://localhost:8001/payment/circuit/-31
重点测试:多次错误,然后慢慢正确,发现刚开始不满足条件,就算是正确的访问地址也不能进行访问,需要慢慢的恢复链路
服务限流
后面总结sentinel再讲
HystrixDashboard
记录通过Hystrix链路访问的成功和失败数量的统计,图表等
1、建module
consumer-hystrix-dashboard9001
2、改pom
<?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-hystrix-dashboard9001</artifactId>
<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>
</project>
3、配置yml
server:
port: 9001
4、主启动配置注解@EnableHystrixDashboard
@SpringBootApplication
@EnableHystrixDashboard
public class CloudConsumerHystrixDashboard9001Application {
public static void main(String[] args) {
SpringApplication.run(CloudConsumerHystrixDashboard9001Application.class, args);
System.out.println("启动成功");
}
}
5、所有Provider微服务提供类(8001/8002/8003)都需要监控依赖配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
6、启动服务访问
http://localhost:9001/hystrix
演示
1、修改provider-hystrix-payment8001
注意:新版本Hystrix需要在主启动类MainAppHystrix8001中指定监控路径
/**
* 注意:新版本Hystrix需要在主启动类中指定监控路径
* 此配置是为了服务监控而配置,与服务容错本身无关,spring cloud升级后的坑
* ServletRegistrationBean因为springboot的默认路径不是"/hystrix.stream",
* 只要在自己的项目里配置上下面的servlet就可以了
*
* @return ServletRegistrationBean
*/
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
// 一启动就加载
registrationBean.setLoadOnStartup(1);
// 添加url
registrationBean.addUrlMappings("/hystrix.stream");
// 设置名称
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
2、9001监控8001
监控地址:http://localhost:8001/hystrix.stream
3、测试地址
正确:http://localhost:8001/payment/circuit/31
错误:http://localhost:8001/payment/circuit/-31
查看dashboard