1 概述
1)服务雪崩是啥?
2)Hystrix介绍
3)Hystrix能干啥?
1,服务降级(fallback)
比如当某个服务繁忙,不能让客户端的请求一直等待,应该立刻返回给客户端一个备选方案
2,服务熔断(break)
当某个服务出现问题,卡死了,不能让用户一直等待,需要关闭所有对此服务的访问,然后调用服务降级
详细讲解:
类似于保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回优好提示,相当于->服务降级->进而熔断->恢复调用链路
比如并发达到1000,我们就拒绝其他用户访问,在有用户访问,就访问降级方法
3,服务限流(flowlimit)
限流,比如秒杀场景,不能访问用户瞬间都访问服务器,限制一次只可以有多少请求
2 服务降级使用
1,服务端降级
1)架包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
- 启动类添加注解@EnableCircuitBreaker
@SpringBootApplication
@EnableCircuitBreaker
public class PaymentHystrixApplication {
public static void main(String[] args) {
SpringApplication.run(PaymentHystrixApplication.class, args);
System.out.println("启动成功");
}
}
3)接口添加@HystrixCommand
/**
* 超时访问,设置自身调用超时的峰值,峰值内正常运行,超过了峰值需要服务降级 自动调用fallbackMethod 指定的方法
* 超时异常或者运行异常 都会进行服务降级
* 设置请求是1.5秒,但是接口请求是3秒
*/
@HystrixCommand(fallbackMethod = "paymentInfoTimeOutHandler", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
})
public String paymentInfoTimeOut(Integer id) {
// int age = 10/0;//程序异常时降级
int second = 3000;
try {
TimeUnit.MILLISECONDS.sleep(second);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "线程池: " + Thread.currentThread().getName() + " paymentInfoTimeOut,id: " + id + "\t"
+ "O(∩_∩)O哈哈~" + " 耗时(秒): " + second;
}
/**
* paymentInfoTimeOut 方法失败后 自动调用此方法 实现服务降级 告知调用者 paymentInfoTimeOut 目前无法正常调用
*/
public String paymentInfoTimeOutHandler(Integer id) {
return "线程池: " + Thread.currentThread().getName() + " paymentInfoTimeOutHandler8001系统繁忙或者运行报错,请稍后再试,id: " + id + "\t"
+ "o(╥﹏╥)o";
}
4)运行结果
2 客户端降级(一般降级处理都放在客户端)
1)架包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2)配置
feign:
hystrix:
enabled: true #如果处理自身的容错就开启
3)启动类添加注解
@EnableHystrix
4 业务类代码
方法一:controller中直接控制
GetMapping("/payment/hystrix/timeout/{id}")
@HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000")
})
public String paymentInfoTimeOut(@PathVariable("id") Integer id) {
int age = 10 / 0;
String result = paymentHystrixService.paymentInfoTimeOut(id);
return result;
}
/**
* 超时访问,设置自身调用超时的峰值,峰值内正常运行,超过了峰值需要服务降级 自动调用fallbackMethod 指定的方法
* <br/>
* 超时异常或者运行异常 都会进行服务降级
*
*/
public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id) {
return "我是消费者80,对方支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
}
方法二:针对方法一重复代码多
@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;
}
并在controller上添加一个注解
@DefaultProperties(defaultFallback = "paymentTimeOutGlobalFallbackMethod")
public class OrderHystrixController {}
在controller中把这个全局方法写出来
public String paymentTimeOutGlobalFallbackMethod() {
return "我是消费者80全局异常稍后处理";
}
方法三 直接提出来公共的处理异常类,这样方便处理每一个接口异常返回信息,解耦
编写公共类
@Component
public class PaymentFallbackServiceImpl implements PaymentHystrixService {
@Override
public String paymentInfoOK(Integer id) {
return "-----服务宕机了";
}
}
更改PaymentHystrixService的注解
@Component
// FeignFallback 客户端的服务降级 针对 provider-payment-hystrix该服务 提供了一个 对应的服务降级类
@FeignClient(value = "PROVIDER-PAYMENT-HYSTRIX", fallback = PaymentFallbackServiceImpl.class)
public interface PaymentHystrixService {
@GetMapping("/payment/hystrix/ok/{id}")
String paymentInfoOK(@PathVariable("id") Integer id);
}
注意:该方法(第三种方法)只有在运行超时(例如服务端出现高并发,宕机),兜底方法才会执行,出现运行时异常则不会执行兜底方法。
如果需要兼顾到运行时异常需要采用第1,2种方法。
3 服务熔断使用
/**
* 服务熔断 超时、异常、都会触发熔断
* 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")// 失败率达到多少后跳闸
})
public String paymentCircuitBreaker(Integer id) {
if (id < 0) {
throw new RuntimeException("******id 不能负数");
}
return Thread.currentThread().getName() + "\t" + "调用成功,流水号: " + UUID.randomUUID();
}
/**
* paymentCircuitBreaker 方法的 fallback,<br/>
* 当断路器开启时,主逻辑熔断降级,该 fallback 方法就会替换原 paymentCircuitBreaker 方法,处理请求
*
* @param id
* @return
*/
public String paymentCircuitBreakerFallback(Integer id) {
return Thread.currentThread().getName() + "\t" + "id 不能负数或超时或自身错误,请稍后再试,/(ㄒoㄒ)/~~ id: " + id;
}
断路器的打开和关闭,是按照一下5步决定的
1,并发此时是否达到我们指定的阈值
2,错误百分比,比如我们配置了60%,那么如果并发请求中,10次有6次是失败的,就开启断路器
3,上面的条件符合,断路器改变状态为open(开启)
4,这个服务的断路器开启,所有请求无法访问(即使上边接口不输入负数,还是返回了fallback方法)
5,在我们的时间窗口期,期间,尝试让一些请求通过(半开状态),如果请求还是失败,证明断路器还是开启状态,服务没有恢复
如果请求成功了,证明服务已经恢复
4 Hystrix 所有配置属性
可在HystrixCommandProperties 这个类中查看
5 Hystrix 服务监控
利用 HystrixDashboard 实现监控
单独创建一个工程作为Hystrix 服务监控
1)架包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
2) 要有springboot的监控组件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
3)启动类 添加@EnableHystrixDashboard
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardApplication.class, args);
System.out.println("启动成功");
}
}
4)在需要监控的服务的启动类中添加
/**
* 注意:新版本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;
}
4)服务启动后指定要监控那个服务
请求后会看到如下图
实心圆有两种含义:
颜色代表实例的健康程度,绿色<黄色<橙色<红色递减
请求两越大实心圆越大
通过实心圆可在大量实例中快速发现故障实例和高压力实例
曲线用来记录两分钟内流量的相对变化,通过它观察流量的上升和下降趋势