文章目录
Hystrix
- 学习视频https://www.bilibili.com/video/BV18E411x7eT
- 源码地址https://gitee.com/zhu_xinmiao/springcloud
服务降级
服务熔断
服务限流
Hystrix支付微服务构建
具体代码部分可看源码。
-
导依赖,pom.xml
<!-- hystrix --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
-
建立配置文件,application.yml
-
给主启动类加上eureka注解
@EnableEurekaClient
-
建service层
/** * 正常访问,肯定ok * @param id * @return */ public String paymentInfo_OK(Integer id) { return "线程池:" + Thread.currentThread().getName() + "paymentInfo_OK,id:" + id + "\t正常"; } @Override public String paymentInfo_TimeOut(Integer id) { int timeNum = 3; try { TimeUnit.SECONDS.sleep(timeNum); } catch (InterruptedException e) { e.printStackTrace(); } return "线程池:" + Thread.currentThread().getName() + "paymentInfo_TimeOut,id:" + id + "\t耗时(秒):" + timeNum; }
-
建controller层
@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; }
-
访问http://localhost:8001/payment/hystrix/ok/31和http://localhost:8001/payment/hystrix/timeout/31,前后端得到service层设定的输出结果即为初步搭建成功。
高并发时订单微服务尝试
新建cloud-consumer-feign-hystrix-order80子工程,作为消费端尝试连接高并发时的支付模块。
-
导依赖,pom.xml
-
建立配置文件,application.yml
-
给主启动类加上feign注解
@EnableFeignClients
-
建service层, 通过@FeignClient注解去调用eureka中对应的微服务
@Component @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT") 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); }
-
建controller层
@GetMapping("/consumer/payment/hystrix/ok/{id}") String paymentInfo_OK(@PathVariable("id") Integer id){ return paymentHystrixService.paymentInfo_OK(id); } @GetMapping("/consumer/payment/hystrix/timeout/{id}") String paymentInfo_TimeOut(@PathVariable("id") Integer id){ return paymentHystrixService.paymentInfo_TimeOut(id); }
-
利用Jmeter给8001端口timeout方法加2w个访问请求,此时再调用消费端去访问支付端的微服务,会出现访问缓慢或是直接超时的问题。
降级容错解决要求
服务降级支付侧
当访问8001端口timeout方法出现超时或是运行出错的时候,需要一个兜底的方案,也可以理解为一个备用方法来取代报错的白叶或很久加载不出来的页面,这就是服务降级。
下面进行一个简单的演示和部分讲解,用的是之前Hystrix支付微服务构建中的service:
-
fallbackMethod = "paymentInfo_TimeOutHandler"指的是双引号中的方法为兜底的方法,一旦paymentInfo_TimeOut这个方法出现异常或是加载超时,就会去找兜底的方法执行。
-
commandProperties = {
@HystrixProperty(name = “execution.isolation.thread.timeoutInMilliseconds”,value = “3000”)
}指的是调用该方法的时限是value中的值,此处为3s,未达到3s的时候正常执行该方法,当该方法运行达到或是超过3s了,就会去执行兜底的方法。
@HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
public String paymentInfo_TimeOut(Integer id) {
int timeNum = 5;
try {
TimeUnit.SECONDS.sleep(timeNum);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "线程池:" + Thread.currentThread().getName() + "paymentInfo_TimeOut,id:" + id
+ "\t耗时(秒):" + timeNum;
}
public String paymentInfo_TimeOutHandler(Integer id) {
int timeNum = 3;
try {
TimeUnit.SECONDS.sleep(timeNum);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "线程池:" + Thread.currentThread().getName() + "系统繁忙或者运行报错,请稍后再试,id:" + id
+ "\t超时了,这是个兜底方法";
}
-
同时,在主启动类中需要加上**@EnableCircuitBreaker**注解
-
然后访问对应微服务
服务降级订单侧
-
主启动类加上**@EnableHystrix**注解
-
支付侧service层时间调为
@HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "5000") }) public String paymentInfo_TimeOut(Integer id) { int timeNum = 3000; //3s<5s,支付侧能正常运行 try { TimeUnit.MILLISECONDS.sleep(timeNum); } catch (InterruptedException e) { e.printStackTrace(); } return "线程池:" + Thread.currentThread().getName() + "paymentInfo_TimeOut,id:" + id + "\t耗时(秒):" + timeNum; }
-
编写订单侧controller方法
@GetMapping("/consumer/payment/hystrix/timeout/{id}") //原理和支付侧相同,超出时限或运行错误进行兜底方法 @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500") }) String paymentInfo_TimeOut(@PathVariable("id") Integer id){ return paymentHystrixService.paymentInfo_TimeOut(id); } public String paymentTimeOutFallbackMethod(Integer id) { return "我是消费者80,对方支付系统繁忙请10秒后再试或者自己运行出错请检查自己"; }
全局服务降级
@RestController
@Slf4j
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod") //全局的兜底方法
public class OrderHystrixController {
@Resource
private PaymentHystrixService paymentHystrixService;
@GetMapping("/consumer/payment/hystrix/timeout/{id}")
@HystrixCommand //有配置就用就近配置,没有配置就用全局兜底方法
String paymentInfo_TimeOut(@PathVariable("id") Integer id){
return paymentHystrixService.paymentInfo_TimeOut(id);
}
//下面是全局fallback方法
public String payment_Global_FallbackMethod(){
return "Global异常处理信息,请稍后再试,o(╥﹏╥)o";
}
}
通配服务降级
-
给service层配上一个fallback
//fallback代表兜底的类,类中实现了每一个方法对应的兜底方法 @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class)
-
对应的fallback类
@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"; } }
-
测试
正常访问ok方法没有问题,当我们关闭8001微服务,也就是服务端宕机的情况,就会跳转到service对应的兜底方法中。
服务熔断案例
- 在service层配置对应的方法,原理同降级类似,出错或是未达到配置要求,就会去寻找兜底方法。
在时间窗口期内请求次数中,失败次数达到设定的失败率时,就会熔断,在短时间内输入正确的参数也会返回兜底方法,直到输入正确次数回到失败率以下或是经过一段时间后系统慢慢恢复,一般来说,这个一段时间是很短的。
// 服务熔断
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties ={
@HystrixProperty(name = "circuitBreaker.enabled",value = "true"), //是否开启断路器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"), //请求次数
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "1000"), //时间窗口期
@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(╥﹏╥)o id:" + id;
}
- controller层
// 服务熔断
@GetMapping("/payment/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
String result = paymentService.paymentCircuitBreaker(id);
log.info("****result: " + result);
return result;
}
- 总结
- 断路器参数
- 断路器打开之后作用
- 全部配置
图形化Dashboard搭建
- 概述
-
写pom,主要用到的是下面这个依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId> </dependency>
-
写yml
server: port: 9001
-
写主启动类,主要是要加上**@EnableHystrixDashboard**注解
-
启动后输入http://localhost:9001/hystrix见到以下界面说明开启成功
-
监控的要点有如下几条
-
被监控程序的pom中要有如下依赖
<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>
-
被监控程序主启动类中需添加以下配置
/** * 此配置是为了服务监控而配置,与服务器容错本身无关,springcloud升级后的坑 * ServletRegistrationBean因为springboot的默认路径不是/hystrix.stream * 只要在自己的项目里配置上下文的servlet就可以了 */ @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; }
-
被监控程序主启动类需要**@EnableCircuitBreaker**注解
-
-
图形化界面介绍