Spring Cloud-Hystrix 服务容错处理

Spring Cloud-Hystrix 服务容错处理

第一节 简介

  微服务架构中存在多个可直接调用的服务,这些服务若在调用时出现故障会导致连锁效应,可能会让整个系统变得不可用,这种情况被称为服务雪崩效应,Hystrix可以用来解决这种情况。

  Hystrix是NetFlix针对微服务分布式系统采用的熔断保护中间件,相当于电路中的保险丝。在微服务的架构下,很多服务都相互依赖,如果不能对相互依赖的服务进行隔离,那么服务本身也有可能发生故障,Hystrix通过HystrixCommand对调用进行隔离,从而阻止故障的连锁效应,能够让接口调用快速识别并迅速恢复正常,或者回退并优雅降级

  目前Hystrix已停止更新。

1.1 简单使用

  创建以一个Maven项目,增加Hystrix依赖。

1
2
3
4
5
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-core</artifactId>
<version>1.5.18</version>
</dependency>

  编写一个HystrixCommand。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MyHystrixCommand extends HystrixCommand<String> {
private final String name;

public MyHystrixCommand(String name) {
super(HystrixCommandGroupKey.Factory.asKey("MyGroup"));
this.name = name;
}

@Override
protected String run() throws Exception {
return this.name + ": " + Thread.currentThread().getName();
}
}

  在启动类中调用上述HystrixCommand。

1
2
3
4
5
public static void main(String[] args){
// 同步调用
String result = new MyHystrixCommand("demo").execute();
System.out.println(result);
}

  启动并观察输出,控制台显示demo: hystrix-MyGroup-1。

  上面是同步调用,异步调用如下。

1
2
3
4
5
public static void main(String[] args) throws InterruptedException, ExecutionException {
// 异步调用
Future<String> future = new MyHystrixCommand("demo").queue();
System.out.println(future.get());
}

1.2 回退支持

  接下来通过增加执行时间模拟调用超时失败的情况。首先改下MyHystrixCommand,增加getFallback方法返回回退内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class MyHystrixCommand extends HystrixCommand<String> {
private final String name;

public MyHystrixCommand(String name) {
super(HystrixCommandGroupKey.Factory.asKey("MyGroup"));
this.name = name;
}

@Override
protected String run() throws Exception {
try {
Thread.sleep(1000 * 10);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
return this.name + ": " + Thread.currentThread().getName();
}

@Override
protected String getFallback() {
return " 失败了 ";
}
}

  重新执行,并观察结果,控制台输出: 失败了 。

1.3 信号量策略配置

  信号量配置方法如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    public MyHystrixCommand(String name) {
// super(HystrixCommandGroupKey.Factory.asKey("MyGroup"));
// 增加信号量策略配置
super(HystrixCommand.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("MyGroup"))
.andCommandPropertiesDefaults(
HystrixCommandProperties.Setter()
.withExecutionIsolationStrategy(
HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE
)
)
);
this.name = name;
}

  之前run方法中输出的当前线程名称,可以用来判断当前是线程隔离还是信号量隔离。

1.3.1 线程池隔离和信号量隔离

  • 信号量隔离适应非网络请求,因为是同步的请求,无法支持超时,只能依靠协议本身
  • 线程池隔离,即每个实例都增加个线程池进行隔离

  信号量隔离方式,每次调用线程,当前请求通过计数信号量进行限制,当信号大于最大请求数(maxConcurrentRequests)时进行限制,调用fallback接口快速返回。

  信号量的调用是同步的,也就是说,每次调用都得阻塞调用方的线程,直到结果返回。这样就导致了无法对访问做超时(只能依靠调用协议超时,无法主动释放)

  线程池隔离方式,通过每次都开启一个单独线程运行。它的隔离是通过线程池,即每个隔离粒度都是个线程池,互相不干扰。

  线程池隔离方式,等于多了一层的保护措施,可以通过hytrix直接设置超时,超时后直接返回。

  系统调用的HystrixCommand的execute是一个阻塞方法,也就是说,如果不合理的设置线程池的大小和超时时间,还是有可能把zuul的线程消耗完。从而失去对服务的保护作用

1.4 线程隔离策略配置

  系统默认采用线程隔离策略,可以通过andThreadPoolPropertiesDefaults来配置线程池的一些参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public MyHystrixCommand(String name) {
// 增加线程隔离策略配置
super(HystrixCommand.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("MyGroup"))
.andCommandPropertiesDefaults(
HystrixCommandProperties.Setter()
.withExecutionIsolationStrategy(
HystrixCommandProperties.ExecutionIsolationStrategy.THREAD
)
)
.andThreadPoolPropertiesDefaults(
HystrixThreadPoolProperties.Setter()
.withCoreSize(10)
.withMaxQueueSize(100)
.withMaximumSize(100)
)
);
this.name = name;
}

1.5 结果缓存

  缓存在开发中经常遇到,比如我们经常用Redis这种第三方缓存数据库来临时存放一些常用数据。在Hystrix中也为我们提供了方法级的缓存。

  可以通过重写getCacheKey来判断是否返回缓存的数据,getCacheKey可以根据参数来生成。

1
2
3
4
5
6
7
8
9
10
11
public class MyHystrixCommand extends HystrixCommand<String> {
private final String name;

......

@Override
protected String getCacheKey() {
// 将name属性作为缓存的Key
return String.valueOf(this.name);
}
}

  为了证明能够用到缓存,我们在run方法中增加一行输出,在多次调用的情况下,如果控制台只输出一次就可以证明后面几次都是走的缓存。

1
2
3
4
5
@Override
protected String run() throws Exception {
System.out.println("get data");
return this.name + ": " + Thread.currentThread().getName();
}

  执行程序,发现报错了,根据错误提示可以知道,缓存的处理取决于请求的上下文,所以我们要首先初始化HystrixRequestContext。

1
Caused by: java.lang.IllegalStateException: Request caching is not available. Maybe you need to initialize the HystrixRequestContext?

  改造main方法,如下所示。

1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) throws InterruptedException, ExecutionException {
// 使用缓存前要先初始化上下文
HystrixRequestContext context = HystrixRequestContext.initializeContext();
// 同步调用
String result = new MyHystrixCommand("demo").execute();
System.out.println(result);
// 异步调用
Future<String> future = new MyHystrixCommand("demo").queue();
System.out.println(future.get());
context.shutdown();
}

  再次执行,成功打印如下内容。

1
2
3
get data
demo: hystrix-MyGroup-1
demo: hystrix-MyGroup-1

  get data只输出一次,表示缓存生效。

1.6 缓存清除

  使用缓存时,当数据发生变更,则必须将缓存中的数据也进行更新,不然就会出现数据脏读的问题。

  改写上面的MyHystrixCommand。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class MyHystrixCommand extends HystrixCommand<String> {
private final String name;
private static final HystrixCommandKey GETTER_KEY = HystrixCommandKey.Factory.asKey("MyKey");

public MyHystrixCommand(String name) {
super(HystrixCommand.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("MyGroup"))
.andCommandKey(GETTER_KEY)
);
this.name = name;
}

// 清除缓存
public static void flushCache(String name) {
HystrixRequestCache.getInstance(GETTER_KEY,
HystrixConcurrencyStrategyDefault.getInstance()).clear(name);
}

@Override
protected String run() throws Exception {
System.out.println("get data");
return this.name + ": " + Thread.currentThread().getName();
}

@Override
protected String getFallback() {
return " 失败了 ";
}

@Override
protected String getCacheKey() {
// 将name属性作为缓存的Key
return String.valueOf(this.name);
}
}

  通过HystrixRequestCache来执行清除操作,修改调用代码执行清除操作。

1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) throws InterruptedException, ExecutionException {
// 使用缓存前要先初始化上下文
HystrixRequestContext context = HystrixRequestContext.initializeContext();
// 同步调用
String result = new MyHystrixCommand("demo").execute();
System.out.println(result);
// 清除缓存
MyHystrixCommand.flushCache("demo");
// 异步调用
Future<String> future = new MyHystrixCommand("demo").queue();
System.out.println(future.get());
}

  输出结果如下,说明缓存已经被清除,再删掉调用测试一下是否只输出一次。

1
2
3
4
get data
demo: hystrix-MyGroup-1
get data
demo: hystrix-MyGroup-2

1.7 合并请求

  每个请求都要通过网络访问远程资源,如果可以把多个请求合并为一个一次执行,将多次网络交互变成一次,就可以极大的节省网络开销。

  首先创建合并请求类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class MyHystrixCollapser extends HystrixCollapser<List<String>, String, String> {
private String name;

public MyHystrixCollapser(String name) {
this.name = name;
}

@Override
public String getRequestArgument() {
return name;
}

@Override
protected HystrixCommand<List<String>> createCommand(Collection<CollapsedRequest<String, String>> collection) {
return new BatchCommand(collection);
}

@Override
protected void mapResponseToRequests(List<String> strings, Collection<CollapsedRequest<String, String>> collection) {
int count = 0;
for (CollapsedRequest<String, String> request : collection) {
request.setResponse(strings.get(count++));
}
}

private static final class BatchCommand extends HystrixCommand<List<String>> {
// requests存放要合并的请求
private final Collection<CollapsedRequest<String, String>> requests;

private BatchCommand(Collection<CollapsedRequest<String, String>> requests) {
super(Setter.withGroupKey(
HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
.andCommandKey(
HystrixCommandKey.Factory.asKey("GetValueForKey")
));
this.requests = requests;
}
@Override
protected List<String> run() throws Exception {
System.out.println(" 真正执行请求......");
ArrayList<String> response = new ArrayList<>();
for (CollapsedRequest<String, String> request : requests) {
response.add(" 返回结果:" + request.getArgument());
}
return response;
}
}
}

  接着编写测试代码。

1
2
3
4
5
6
7
public static void main(String[] args) throws InterruptedException, ExecutionException {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
Future<String> f1 = new MyHystrixCollapser("demo").queue();
Future<String> f2 = new MyHystrixCollapser("demo123").queue();
System.out.println(f1.get() + "=" + f2.get());
context.shutdown();
}

  控制台输出结果如下,可以看出两个请求合并在run方法中执行了一次。

1
2
真正执行请求......
返回结果:demo= 返回结果:demo123

第二节 在Spring Cloud中使用Hystrix

2.1 简单使用

  新建一个Maven项目,并引入如下依赖。

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

  在启动类中增加@EnableHystrix或@EnableCircuitBreaker(@EnableHystrix包含@EnableCircuitBreaker)。

  然后编写一个调用接口的方法,用@HystrixCommand注解标注,用于指定依赖服务调用延迟或失败时调用的方法。

1
2
3
4
5
6
@GetMapping("/callHello")
@HystrixCommand(fallbackMethod = "defaultCallHello")
public String callHello() {
String result = restTemplate.getForObject("http://localhost:8081/house/hello", String.class);
return result;
}

  当调用失败出发熔断时会用defaultCallHello方法来回退具体的内容。

1
2
3
public String defaultCallHello() {
return "fail";
}

  我们只要不启动端口所在的服务,调用/callHello接口,就可以看到返回的内容为fail。

  去掉启动类上的@EnableHystrix注解,重启服务,并再次调用/callHello接口,就可以看到熟悉的错误信息。

2.2 配置详解

  HystrixCommand中除了fallbackMethod外还有很多配置,如下所示。

  • hystrix.command.default.execution.isolation.strategy:指定隔离策略,包括THREAD和SEMAPHORE,分别表示线程隔离和信号量隔离,其中线程隔离在单独的线程上执行,并发请求受线程池大小的限制,而信号量隔离则在调用的线程上执行,并发请求受信号量计数器的限制。
  • hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds:配置用于HystrixCommand执行的超时时间设置,当执行时间超过设定的值时会进入服务降级处理,单位是毫秒,默认值为1000。
  • hystrix.command.default.execution.timeout.enabled:是否启用设置的超时时间,默认为true。
  • hystrix.command.default.execution.isolation.thread.interruptOnTimeout:确定HystrixCommand执行超时后是否要中断它,默认为true。
  • hystrix.command.default.execution.isolation.thread.interruptOnConcel:确定HystrixCommand执行被取消时是否要中断它,默认为false。
  • hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests:指定Hystrix使用信号量策略时最大的并发请求数。
  • hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests:如果并发数达到设定值,请求会被拒绝和抛出异常并且fallback不会被调用,默认值为10。
  • hystrix.command.default.fallback.enabled.:确定当执行失败或请求被拒绝时,是否会尝试调用hystrixCommand.getFallback(),默认为true。
  • hystrix.command.default.circuitBreaker.enabled:用来跟踪circuit的健康性,若未达标则让request短路,默认为true。
  • hystrix.command.default.circuitBreaker.requestVolumeThreshold:用来设置一个rolling window内最小的请求数。如果设为20,那么当一个rolling window的时间内收到19个请求,即使全部失败也不会触发circuit break,默认值为20。
  • hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds:用来设置一个触发短路的时间值,比如设为5000,则当触发circuit break后的5000毫秒内都会拒绝request,即5000毫秒后才会关闭circuit。默认值为5000。
  • hystrix.command.default.circuitBreaker.errorThresholdPercentage:用来设置误差阈值,当错误率超过此值时,所有请求都会出发fallback,默认为50。
  • hystrix.command.default.circuitBreaker.forceOpen:如果配置为true,将强制打开熔断器,在此状态下将拒绝所有请求,默认为false。
  • hystrix.command.default.circuitBreaker.forceClosed:如果配置为true,将强制关闭熔断器,在此状态下,无论错误率有多高,都允许请求,默认为false。
  • hystrix.command.default.metrics.rollingStats.timeInMilliseconds:设置统计的时间窗口值,单位为毫秒。circuit break的打开会根据1个rolling window的统计来计算。若rolling window被设为10000毫秒,则rolling window会被分为多个buckets,每个bucket包含success、failure、timeout、rejection的次数的统计信息。默认值为10000毫秒。
  • hystrix.command.default.metrics.rollingStats.numBuckets:设置一个rolling window被划分的梳理,若numBuckets=10、rolling window=10000,那么一个bucket的时间即1秒。必须符合rolling window%numBuckets==0。默认值为10。
  • hystrix.command.default.metrics.rollingPercentile.enabled:是否开启指标的计算和跟踪,默认为true。
  • hystrix.command.default.metrics.rollingPercentile.timeInMilliseconds:设置rolling percentile window的时间,默认值为60000毫秒。
  • hystrix.command.default.metrics.rollingPercentile.numBuckets:设置rolling percentile window的numBuckets,默认值为6。
  • hystrix.command.default.metrics.rollingPercentile.bucketSize:如果bucket size=100、window=10秒,若这10秒里有500次执行,只有最后100次执行会被统计到bucket里去。增加该值会增加内存开销及排序的开销。默认值为100。
  • hystrix.command.default.metrics.healthSnapshot.intervalInMilliseconds:用来计算影响断路器状态的健康快照的间隔等待时间,默认值为500毫秒。
  • hystrix.command.default.requestCache.enabled:是否开启请求缓存功能,默认为true。
  • hystrix.command.default.requestLog.enabled:记录日志到HystrixRequestLog,默认为true。
  • hystrix.collapser.default.maxRequestsInBatch:单次批处理的最大请求数,达到该数量时触发批处理,默认为Integer.MAX_VALUE。
  • hystrix.collapser.default.timerDelayInMilliseconds:触发批处理的延迟,延迟也可以为创建批处理的时间与该值的和,默认值为10毫秒。
  • hystrix.collapser.default.requestCache.enabled:是否启用对HystrixCollapser.execute()和HystrixCollapser.queue()的请求缓存,默认值为true。
  • hystrix.threadpool.default.coreSize:并发执行的最大线程数,默认值为10。
  • hystrix.threadpool.default.maxQueueSize:BlockingQueue的最大队列数。当设为-1时会使用SynchronousQueue;值为正数时会使用LinkedBlockingQueue。该设置只会在初始化时有效,之后不能修改threadpool的queue size。默认值为-1。
  • hystrix.threadpool.default.queueSizeRejectionThreshold:即使没有达到maxQueueSize,但若达到该值,请求也会被拒绝。因为maxQueueSize不能被动态修改,而此参数则可以。如果设为-1则此字段不起作用。
  • hystrix.threadpool.default.keepAliveTimeMinutes:设置存活时间,单位为分钟。如果coreSize小于maximumSize,那么该属性控制一个线程从使用完成到释放的时间。默认值为1分钟。
  • hystrix.threadpool.default.allowMaximumSizeToDivergeFormCoreSize:该属性允许maximumSize的配置生效。那么该值可以等于或高于coreSize。设置coreSize小于maximumSize会创建一个线程池,此线程池会支持maximumSize并发,但在相对不活动期间将向系统返回线程。默认为false。
  • hystrix.threadpool.default.metrics.rollingStats.timeInMilliseconds:设置滚动时间窗的时间,单位为毫秒,默认值为10000。
  • hystrix.threadpool.default.metrics.rollingStats.numBuckets:设置滚动时间窗划分桶的数量,默认值为10。

  以上配置信息只需在接口的方法上面使用HystrixCommand注解,并指定对应属性即可。

1
2
3
4
5
6
7
8
9
@HystrixCommand(fallbackMethod = "defaultCallHello", 
commandProperties = {
@HystrixProperty(name = "execution.isolation.strategy", value = "THREAD")
})
@GetMapping("/callHello")
public String callHello() {
String result = restTemplate.getForObject("http://localhost:8081/house/hello", String.class);
return result;
}

2.3 Feign整合Hystrix服务容错

  创建一个新的Maven项目,增加EurekaClient、Feign和Hystrix的依赖,然后在属性文件中开启Feign对Hystrix的支持。

1
2
# 开启Feign对Hystrix的支持
feign.hystrix.enabled=true

2.3.1 Fallback方式

  @FeignClient中指定fallback进行回退。

1
2
3
4
5
6
7
@FeignClient(value = "eureka-client-user-service", 
configuration = FeignConfiguration.class,
fallback = UserRemoteClientFallback.class)
public interface UserRemoteClient {
@GetMapping("/user/hello")
String hello();
}

  创建UserRemoteClientFallback实现UserRemoteClient接口和其方法,返回回退时的内容。

1
2
3
4
5
6
7
@Component
public class UserRemoteClientFallback implements UserRemoteClient {
@Override
public String hello() {
return "fail";
}
}

  其余部分(配置和/callHello接口等)和feign-demo相同。

  不要开启eureka-client-user-service服务,然后启动此项目,访问/callHello接口,会触发回退。在这种情况下,若接口调用了多个服务的接口,那么只有eureka-client-user-service服务会没数据,不会影响别的服务调用,但如果不使用Hystrix回退处理,整个请求都会失败。

  关闭Hystrix断路器。

1
feign.hystrix.enabled=false

  重启服务,并访问,结果变为500。

2.3.1 FallbackFactory方式

  通过fallback已经可以实现服务不可用时回退的功能,如果我们想知道触发回退的原因,可以使用FallbackFactory来实现回退功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Component
public class UserRemoteClientFallbackFactory implements FallbackFactory<UserRemoteClient> {
private Logger logger = LoggerFactory.getLogger(UserRemoteClientFallbackFactory.class);

@Override
public UserRemoteClient create(Throwable throwable) {
logger.error("UserRemoteClient回退:", throwable);
return new UserRemoteClient() {
@Override
public String hello() {
return "false";
}
};
}
}

  在@FeignClient中通过fallbackFactory指定回退处理类。

1
2
3
4
5
6
7
@FeignClient(value = "eureka-client-user-service",
configuration = FeignConfiguration.class,
fallbackFactory = UserRemoteClientFallbackFactory.class)
public interface UserRemoteClient {
@GetMapping("/user/hello")
String hello();
}

  重启并访问接口,日志打印如下内容。

1
2
3
ERROR 18244 --- [-user-service-1] c.l.h.UserRemoteClientFallbackFactory    : UserRemoteClient回退:
java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: eureka-client-user-service
......

2.4 Feign中禁用Hystrix

  除了配置文件禁用Hystrix外,还可以通过代码的方式禁用某个客户端。

1
feign.hystrix.enabled=false

  重写feignBuilder方法。

1
2
3
4
5
6
7
8
@Configuration
public class FeignNoHystrixConfiguration {
@Bean
@Scope("prototype")
public Feign.Builder feignBuilder() {
return Feign.builder();
}
}

  配置部分禁用Hystrix。

1
2
3
4
5
//关闭Hystrix(会导致所有的xxx都关闭,不管其它配置是否开启也会关闭,这是个坑要注意下)
@FeignClient(value="xxx",configuration=FeignNoHystrixConfiguration.class)
public interface Test {
......
}

第三节 Hystrix监控

  在微服务架构中,Hystrix除了容错还提供了实时监控功能。在服务调用时,Hystrix会实时累积关于HystrixCommand的执行信息,比如每秒的请求数、成功数等。

  更多内容可以参考官方文档:Metrics-and-Monitoring

Hystrix监控需要两个必备条件:

  1. 必须引入Actuator依赖。
  2. 必须引入Hystrix依赖,Spring Cloud必须在启动类添加@EnableHystrix开启。

  改造项目并增加Actuator依赖。

1
2
3
4
5
<!-- Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

  不要忘记开放监控端点。

1
2
# 开放监控端点
management.endpoints.web.exposure.include=health,info,hystrix.stream

  启动服务,访问http://localhost:8085/actuator/hystrix.stream


第四节 整合Dashboard查看监控数据

  上述虽然已开启监控功能,但数据是以字符串的形式展现的,实际使用非常不方便,我们可以引入hystrix-dashboard对监控进行图形化显示。

  引入依赖。

1
2
3
4
5
<!-- hystrix-dashboard -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>

  启动类添加注解@EnableHystrixDashboard。

1
2
3
4
5
6
7
8
@EnableHystrixDashboard 
@EnableDiscoveryClient
@EnableFeignClients
@EnableHystrix
@SpringBootApplication
public class HystrixDemoApplication {
......
}

  还要注意要在配置文件中配置服务名称和服务端口

1
2
server.port=8085
spring.application.name=eureka-client-hystrix-demo

  启动项目,直接访问http://localhost:8085/hystrix,结果如下。

  点击Monitor Stream,结果如下。


第五节 Turbine聚合集群数据

5.1 Turbine使用

  首先引入Turbine依赖。

1
2
3
4
5
<!-- turbine -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>

  启动类配置开启@EnableTurbine和@EnableDiscoveryClient。

1
2
3
4
5
6
7
8
9
@EnableHystrixDashboard
@EnableTurbine
@EnableDiscoveryClient
@EnableFeignClients
@EnableHystrix
@SpringBootApplication
public class HystrixDemoApplication {
......
}

  属性文件中添加如下配置。

1
2
3
4
5
6
# 配置需要聚合的服务名称
turbine.app-config=eureka-client-hystrix-demo
# turbine需要聚合的集群名称
turbine.aggregator.cluster-config=default
# 集群名表达式
turbine.cluster-name-expression=new String("default")

  重启服务,访问http://localhost:8085/turbine.stream。

  获取集群的监控数据。Turbine会通过在Eureka中查找服务的homePageUrl加上hystrix.stream来获取其他服务的监控数据,并汇总显示。

5.2 context-path导致监控失败

  如果被监控的服务中设置了context-path,就会导致turbine无法获取监控数据。需要在配置文件中指定turbine.instanceUrlSuffix属性。

1
2
# 解决context-path导致监控失败
turbine.instanceUrlSuffix=/sub/hystrix.stream

  sub用于监控服务的context-path。这种方式是全局配置,一般情况下会使用一个集群去监控多个服务,如果每个服务的context-path都不一样,这样的配置就无法适配,需要对每个服务做一个集群,然后配置集群对应的context-path。

1
turbine.instanceUrlSuffix.<集群名称>=/sub/hystrix.stream

参考博客和文章书籍等:

《Spring Cloud微服务-入门、实战和进阶》

因博客主等未标明不可引用,若部分内容涉及侵权请及时告知,我会尽快修改和删除相关内容