Hystrix (停更)
前言
服务雪崩,多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的“扇出“。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”。
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,粤致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。
通常当你发现一个模块下的某个实例失败后,这时候这个模块依然还会接收流量,然后这个有问题的模块还调用了其他的模块,这样就会发生级联故障,或者叫雪崩。
Hystrix 是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix 能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
"断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(Fall Back),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。
主要应用
Fall Back 服务降级
服务降级,当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。
触发降级的情况:程序运行异常、超时、熔断触发、线程池/信号占满等。
Break 服务熔断
服务熔断也称服务隔离,来自于Michael Nygard 的《Release It》中的CircuitBreaker应用模式。服务熔断是服务降级的措施。服务熔断对服务提供了proxy,防止服务不可能时,出现串联故障(cascading failure),导致雪崩效应。
服务熔断和服务降级所考虑关注的目标也不一样,熔断是每个微服务都需要的,是一个框架级的处理,而服务降级一般是关注业务,对业务进行考虑,抓住业务的层级,从而决定在哪一层上进行处理:比如在IO层,业务逻辑层,还是在外围进行处理。
Flow Limit 服务限流
限流主要的作用是保护服务节点或者集群后面的数据节点,防止瞬时流量过大使服务和数据崩溃(如前端缓存大量实效),造成不可用;还可用于平滑请求。
构建
依赖坐标
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
Fall Back 服务降级
返回一个符合预期的、可处理的备选响应
服务端
启动类
启动类添加@EnableCircuitBreaker
注解,开启降级支持
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
//开启支持
@EnableCircuitBreaker
public class PaymentHystrixApplication8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentHystrixApplication8001.class, args);
}
}
使用 service 层
使用@HystrixCommand
注解,一旦调用服务方法失败抛出错误信息后或超出规定时间,会自动调用标注好的指定方法。
fallbackMethod
:指定处理方法。
commandProperties
:指定方法执行时常,超过时长进行 Fall Back。
@Service
public class PaymentService {
/**
* 超时错误
* @param id id
* @return string
*/
@SneakyThrows
@HystrixCommand(fallbackMethod = "timeoutHandler", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
public String timeout(Long id) {
int time = 3;
TimeUnit.SECONDS.sleep(time);
return id + " -- " +"线程池:" + Thread.currentThread().getName() + " --- Timeout";
}
/**
*
* 超时处理方法
*/
public String timeoutHandler(Long id) {
return id + " -- " +"线程池:" + Thread.currentThread().getName() + " --- TimeoutHandler";
}
}
客户端
配置
feign:
# 开启降级支持
hystrix:
enabled: true
启动类
使用@EnableHystrix
注解开启降级支持
@SpringBootApplication
@EnableFeignClients
//开启降级支持
@EnableHystrix
public class OrderHystrix80 {
public static void main(String[] args) {
SpringApplication.run(OrderHystrix80.class, args);
}
}
使用 controller 层
使用@HystrixCommand
注解,一旦调用服务方法失败抛出错误信息后或超出规定时间,会自动调用标注好的指定方法。
fallbackMethod
:指定处理方法。
commandProperties
:指定方法执行时常,超过时长进行 Fall Back。
@RestController
@RequestMapping("/consumer")
public class OrderController {
@Resource
private IPaymentService paymentService;
@GetMapping("timeout/{id}")
@HystrixCommand(fallbackMethod = "timeoutFallback", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
})
public String timeout(@PathVariable("id") Long id) {
return paymentService.paymentInfoTimeout(id);
}
/**
* 降级解决方法
*/
public String timeoutFallback(Long id) {
return id + " --- 对方系统繁忙,请稍后再试";
}
}
全局Fall Back
在 Controller 或 Service 上添加注解 @DefaultProperties
可配置全局 FallBack 方法,没有使用指定 FallBack 方法 的接口抛出异常后会调用全局 FallBack。如果要使用 FallBack 必须添加 @HystrixCommand
注解。
defaultFallback
:指定默认 FallBack 方法
@RestController
@RequestMapping("/consumer")
// 指定全局FallBack方法
@DefaultProperties(defaultFallback = "globalFallBack")
public class OrderController {
@Resource
private IPaymentService paymentService;
@GetMapping("/ok/{id}")
@HystrixCommand
public String ok(@PathVariable("id") Long id) {
return paymentService.paymentInfoOk(id);
}
@GetMapping("timeout/{id}")
@HystrixCommand(fallbackMethod = "timeoutFallback", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
})
public String timeout(@PathVariable("id") Long id) {
return paymentService.paymentInfoTimeout(id);
}
/**
* 特殊FallllBack
*/
public String timeoutFallback(Long id) {
return id + " --- 对方系统繁忙,请稍后再试";
}
/**
* 全局FallBack
*/
public String globalFallBack() {
return "系统正忙,请稍后重试";
}
}
实现service接口
实现 service 接口处理 FallBack 可不在 Controller 中添加@HystrixCommand
注解,也可以使得 FallBack 方法与业务逻辑解耦,同时可处理每一个接口 FallBack。
接口
在接口中需要指定 fallback 的实现类
@Component
//在接口中指定 fallback 的实现类
@FeignClient(value = "PROVIDER-PAYMENT-HYSTRIX", fallback = PaymentFallbackServiceImpl.class)
public interface IPaymentService {
/**
* 正常请求
* @param id id
* @return string
*/
@GetMapping("/payment/ok/{id}")
String paymentInfoOk(@PathVariable("id") Long id);
/**
* timeout 请求
* @param id id
* @return string
*/
@GetMapping("/payment/timeout/{id}")
String paymentInfoTimeout(@PathVariable("id") Long id);
}
实现
@Component
public class PaymentFallbackServiceImpl implements IPaymentService{
@Override
public String paymentInfoOk(Long id) {
return "fall back ---- ok";
}
@Override
public String paymentInfoTimeout(Long id) {
return "fall back ---- tiemout";
}
}
Circuit Breaker 服务熔断
熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务出错不可用或者响应时间太长时,几会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后,恢复调用链路。
熔断打开:请求不在进行调用当前服务,内部设置时钟一般为MTTR(平均故障处理时间),当打开时长达到所设时钟则进入半熔断状态。
熔断半开:部分请求根据规则调用当前服务,如果请求成功且符合规则则认为当前服务恢复正常,关闭熔断。
熔断关闭:所有请求可以调用当前服务。
Service层
使用@HystrixCommand
注解
fallbackMethod
:指定熔断处理方法
参数:@HystrixProperty
enabled
:是否开启熔断机制,默认关闭
requestVolumeThreshold
:请求阈值,默认20
sleepWindowInMilliseconds
:快照时间窗口期,默认10
errorThresholdPercentage
:失败率阈值,默认50
以下配置表示:开启断路器,在15秒内,10个请求的失败率达到60%则开启熔断机制。
/**
* 服务熔断
*/
@HystrixCommand(fallbackMethod = "circuitBreakerFallback", commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"), //是否开启断路器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), //请求阈值
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "15000"), //快照时间窗口期
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60") //失败率阈值
})
public String circuitBreaker(Long id) {
if (id < 10) {
throw new RuntimeException("服务熔断了...");
}
return Thread.currentThread().getName() + " --- " + "OK";
}
/**
* 服务熔断处理
*/
public String circuitBreakerFallback(Long id) {
return id + " --- false";
}
Dashboard
监控仪表盘
依赖坐标
<!-- hystrix-dashboard -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
配置
server:
port: 9001
启动类
使用@EnableHystrixDashboard
注解开启仪表盘
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardApplication9001 {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardApplication9001.class, args);
}
}
验证
访问:http://localhost:9001/hystrix
被监控服务
依赖坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
配置类
@Configuration
public class HystrixConfig {
@Bean
public ServletRegistrationBean servletRegistrationBean() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();;
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
监控
在监控页面输入:http://{服务器IP}:{服务端口}/hystrix.stream
填写延迟及标题即可。