Spring Cloud Hystrix 是基于 Netflix 公司的开源组件 Hystrix 实现的,它提供了熔断器功能,能够有效地阻止分布式微服务系统中出现联动故障,以提高微服务系统的弹性。Spring Cloud Hystrix 具有服务降级、服务熔断、线程隔离、请求缓存、请求合并以及实时故障监控等强大功能。
在微服务系统中,Hystrix 能够帮助我们实现以下目标:
Hystrix 提供了服务降级功能,能够保证当前服务不受其他服务故障的影响,提高服务的健壮性。
服务降级的使用场景有以下 2 种:
Hystrix的降级策略:
Hystrix提供了如下三种降级策略:
熔断降级: 默认在10秒内,发送20次请求,失败率达到50%,就会触发熔断降级。
超时降级: 默认请求的响应时间超过1秒,就会触发超时降级。
资源隔离降级
- 信号量隔离 调用线程与hystrixCommand线程是同一个线程。同步方式。资源消耗小。不支持超时。
- 线程池隔离 调用线程与hystrixCommand线程不是同一个线程。异步方式。支持超时。可以为每个服务单独分配线程池。大量线程的上下文切换带来的开销比较大。
改造现有服务
1.pom文件引入spring-boot-starter-netflix-hystrix
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-hystrixartifactId>
<version>2.0.2.RELEASEversion>
dependency>
2.在controller中需要增加熔断功能的接口添加注解@HystrixCommand, 详细参数见 Hystrix参数
@RestController
@RequestMapping("hystrix")
public class HystrixController {
@Autowired
private HystrixService hystrixService;
// 熔断降级
@GetMapping("{num}")
@HystrixCommand(fallbackMethod="circuitBreakerFallback", commandProperties = {
@HystrixProperty(name=HystrixPropertiesManager.CIRCUIT_BREAKER_ENABLED, value = "true"),
// 是否开启熔断器
@HystrixProperty(name=HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD,value = "20"), // 统计时间窗内请求次数
@HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE, value = "50"),// 在统计时间窗内,失败率达到50%进入熔断状态
@HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS, value = "5000"), // 休眠时间窗口
@HystrixProperty(name = HystrixPropertiesManager.METRICS_ROLLING_STATS_TIME_IN_MILLISECONDS, value = "10000") // 统计时间窗
})
public String testCircuitBreaker(@PathVariable Integer num, @RequestParam String name) {
if (num % 2 == 0) {
return "请求成功";
} else {
throw RunTimeException("");
}
}
// fallback方法的参数个数、参数类型、返回值类型要与原方法对应,fallback方法的参数多加个Throwable
public String circuitBreakerFallback(Integer num, String name) {
return "请求失败,请稍后重试";
}
// 超时降级
@GetMapping
@HystrixCommand(fallbackMethod = "timeoutFallback", commandProperties = {
@HystrixProperty(name = HystrixPropertiesManager.EXECUTION_TIMEOUT_ENABLED, value = "true"),
// 是否开启超时降级
@HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS, value = "10000"),
// 请求的超时时间,默认10000
@HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_INTERRUPT_ON_TIMEOUT, value = "true")
// 当请求超时时,是否中断线程,默认true
})
public String testTimeout(@RequestParam String name) throws InterruptedException{
Thread.sleep(200)
return "success";
}
public String timeoutFallback(String name) {
return "请求超时,请稍后重试";
}
// 资源隔离(线程池)触发降级
@GetMapping("isolation/threadpool")
@HystrixCommand(fallbackMethod = "isolationFallback",
commandProperties = {
@HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY, value = "THREAD")
},
threadPoolProperties = {
@HystrixProperty(name = HystrixPropertiesManager.CORE_SIZE, value = "10"),
@HystrixProperty(name = HystrixPropertiesManager.MAX_QUEUE_SIZE, value = "-1"),
@HystrixProperty(name = HystrixPropertiesManager.QUEUE_SIZE_REJECTION_THRESHOLD, value = "2"),
@HystrixProperty(name = HystrixPropertiesManager.KEEP_ALIVE_TIME_MINUTES, value = "1"),
}
)
public String testThreadPoolIsolation(@RequestParam String name) throws InterruptedException {
Thread.sleep(200)
return "success";
}
public String isolationFallback(String name) {
return "资源隔离拒绝,请稍后重试";
}
// 信号量资源隔离
@GetMapping("isolation/semaphore")
@HystrixCommand(fallbackMethod = "isolationFallback",
commandProperties = {
@HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY, value = "SEMAPHORE"),
@HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, value = "2")
}
)
public String testSemaphoreIsolation(@RequestParam String name) throws InterruptedException {
Thread.sleep(200)
return "success";
}
public String isolationFallback(String name) {
return "资源隔离拒绝,请稍后重试";
}
}
3.全局参数application.yml @HystrixCommand注解的配置优先于Hystrix全局配置
hystrix:
command:
default:
circuitBreaker:
enabled: true
requestVolumeThreshold: 20
errorThresholdPercentage: 50
sleepWindowInMilliseconds: 5000
execution:
timeout:
enabled: true
isolation:
thread:
timeoutInMilliseconds: 2000
interruptOnTimeout: true
semaphore:
maxConcurrentRequests: 10
strategy: THREAD
metrics:
rollingStats:
timeInMilliseconds: 10000
threadpool:
default:
coreSize: 10
maximumSize: 19
allowMaximumSizeToDivergeFromCoreSize: false
keepAliveTimeMinutes: 1
maxQueueSize: -1
queueSizeRejectionThreshold: 5
4.在启动类添加注解 @EnableCircuitBreaker 注解或者 @EnableHystrix 注解
@SpringBootApplication
@EnableCircuitBreaker
public class HystrixSpringApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixSpringApplication.class, args);
}
}
在服务提供方定义 feign client 接口 以及 fallback或者fallbackFactory,在服务消费方定义具体的降级策略。
1.引入依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
<version>2.0.2.RELEASEversion>
dependency>
<dependency>
<groupId>io.github.openfeigngroupId>
<artifactId>feign-httpclinetartifactId>
<version>9.7.0version>
dependency>
<dependency>
<groupId>io.github.openfeigngroupId>
<artifactId>feign-hystrixartifactId>
<version>9.7.0version>
dependency>
2.定义Feign调用接口,其中fallbackFactory中为试下的fallback方法
// fallbackFactory 实现
@FeignClient(value = "hystrixProject", url="http://localhost:8085", fallbackFactory = HystrixServerFallbackFactory.class)
public interface HystrixServer {
@GetMapping("/test")
String test();
}
// fallback 实现
@FeignClient(value = "hystrixProject", url="http://localhost:8085", fallback = HystrixServerFallback.class)
public interface HystrixServer {
@GetMapping("/test")
String test();
}
3.定义HystrixServerFallbackFactory.class
import feign.hystrix.FallbackFactory;
@Component
public class HystrixServerFallbackFactory implements FallbackFactory<HystrixServer> {
@Override
public HystrixServer create(Throwable throwable) {
return new HystrixServer() {
@Override
public String test() {
return "服务降级";
}
}
}
}
4.定义HystrixServerFallback.class
@Component
public class HystrixServerFallback implements HystrixServer {
public String test() {
return "服务降级";
}
}
5.全局配置,application.yml
老版本配置:对应于本文的版本
feign:
hystrix:
enabled: true
新版本配置:
feign:
circuitbreaker:
enabled: true //开启服务降级
6.启动类增加注解
@SpringBootApplication
@EnableFeignClients
public class HystrixDashboardApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardApplication.class, args);
}
}
这些参数可以应用于Hystrix的THREAD和SEMAPHORE策略
hystrix.threadpool.default.coreSize 并发执行的核心线程数,默认10。不能设置为0,初始化setter的时候会出现异常。
hystrix.threadpool.default.maximumSize 并发执行的最大线程数,默认10。 This property sets the maximum thread-pool size. This is the maximum amount of concurrency that can be supported without starting to reject HystrixCommand
s. Please note that this setting only takes effect if you also set allowMaximumSizeToDivergeFromCoreSize
. Prior to 1.5.9, core and maximum sizes were always equal.
hystrix.threadpool.default.maxQueueSize BlockingQueue的最大队列数,当设为-1,会使用SynchronousQueue,值为正时使用LinkedBlcokingQueue。Note: This property only applies at initialization time since queue implementations cannot be resized or changed without re-initializing the thread executor which is not supported.
hystrix.threadpool.default.queueSizeRejectionThreshold 队列截断阈值。即使maxQueueSize没有达到,达到queueSizeRejectionThreshold该值后,请求也会被拒绝。如果maxQueueSize == -1,该字段将不起作用。
hystrix.threadpool.default.keepAliveTimeMinutes 线程空闲存活时间。如果corePoolSize和maxPoolSize设成一样(默认实现)该设置无效。
hystrix.threadpool.default.metrics.rollingStats.timeInMilliseconds 线程池统计指标的时间,默认10000。
hystrix.threadpool.default.metrics.rollingStats.numBuckets 将rolling window划分为n个buckets,默认10。
建议设置值:
timeoutInMilliseconds:依赖外部接口时,推荐配置比rpc超时时间稍短,否则可能无法发挥作用。
maxConcurrentRequests:估算值:(单机QPS*响应时间)2/1000,2为预留一倍值,可以自行调整。
coreSize:估算值:(单机qps响应时间)*1.5/1000,1.5为预留0.5倍buffer,该值可以适当减少,因为线程池会有排队队列。
maxQueueSize:仅在allowMaximumSizeToDivergeFromCoreSize(是否开启动态线程数)为true时才生效。建议设置core的两倍大小。
1.新建Hystrix-DashBoard项目,引入pom依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-hystrixartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-hystrix-dashboardartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
dependencies>
2.application.yml文件配置
server:
port: 8082
spring:
application:
name: hystrix-dashboard
hystrix:
dashboard:
proxy-stream-allow-list: "*"
3.在启动类上添加@EnableHystrixDashboard注解开启Dashboard
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardApplication.class, args);
}
}
4.启动服务访问地址 “http://localhost:7020/hystrix”,可以看到Hystrix Dashboard入口
调用的格式页面中已给出,第一个文本框中是需要监控的服务或者集群的地址,这里暂时不需要监控集群,所以我们输入监控的服务地址即可,即输入“http://localhost:7010/actuator/hystrix.stream”;
“Delay”文本框中是轮询调用服务监控信息的延迟时间,默认是2000ms(2s);
“Title”文本框中是监控页面的标题,这里我们输入“hystrix服务调用商品服务”,然后单击“Monitor Stream”就可以进入Hystrix Dashboard页面,如图所示。
因为Hystrix是通过监控服务调用监控信息的,并且需要访问被监控服务的“/hystrix.stream”接口,而这个接口也是Actuator监控的一个端点,所以需要在服务调用者的pom.xml文件中添加Actuator依赖,并开放监控的端点信息。
1.被监控服务pom文件增加依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-hystrixartifactId>
<version>RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
dependencies>
2.application.yml增加配置信息
# 暴漏监控信息
management:
endpoints:
web:
exposure:
include: "*"