SpringCloud学习笔记(五、SpringCloud Netflix Hystrix)

目录:

  • Hystrix简介
  • 线程隔离:线程池、信号量
  • 服务降级、服务熔断、请求缓存、请求合并
  • Hystrix完整流程、Hystrix属性值
  • 注解方式实现Hystrix
  • Hystrix Dashboard

Hystrix简介:

1、Hystrix是什么

Hystrix是Netflix的一款开源的布式容错和延迟库,目的是用于隔离分布式服务的故障。它提供了优雅的服务降级、熔断机制,使得服务能够快速的失败,而不是一直等待响应,并且它还能从失败中快速恢复。

说白了Hystrix就是封装了服务之间异常调用的一个框架(之前看到过微服务界的一个大佬说的一句话,很有道理:一个好的服务架构一定是具有自诊断功能的)。

2、Hystrix解决的问题

  • 限制分布式服务的资源使用,当某一个调用的服务出现问题时不会影响其他服务的调用,通过线程隔离信号量来实现。
  • 提供了优雅的降级机制超时降级、资源不足时降级;降级后可通过降级接口返回托底数据。
  • 提供了熔断机制,当失败率达到了阀值时会自动降级,并且可以快速恢复。
  • 提供了请求缓存和请求合并的实现

线程隔离:线程池、信号量:

我们知道Hystrix对于限制分布式服务的资源使用是通过线程隔离信号量来实现了,那我们就来说说这两个。

1、线程隔离之线程池

)什么是线程隔离

线程隔离其实就是对线程资源的隔离,它可以将系统资源分开,在发生故障的时候缩小影响范围

如登录时需要sso和加载广告,当用户登录时加载广告的接口挂了,那么便会影响用户的登录,但其实主流程只是sso,广告挂了也不能影响主流程啊;而线程隔离便可以解决这一问题。

Hystrix的线程隔离便是,把Tomcat请求的任务转交给Hystrix内部的线程去执行,这样在Hystrix开启线程后就可以释放Tomcat线程资源,从而Tomcat便可以响应更多的请求,遭遇过Hystrix将任务执行完后再把结果交给Tomcat。

)Hystrix线程隔离demo

  1 public class HystrixCommand4ThreadPool extends HystrixCommand<String> {
  2 
  3     private final String name;
  4 
  5     public HystrixCommand4ThreadPool(String name) {
  6         super(Setter
  7                 // 线程组名称
  8                 .withGroupKey(HystrixCommandGroupKey.Factory.asKey("ThreadPoolGroup"))
  9                 // 命令名称
 10                 .andCommandKey(HystrixCommandKey.Factory.asKey("ThreadPoolCommandKey"))
 11                 // 线程池名称
 12                 .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("ThreadPoolKey"))
 13                 .andCommandPropertiesDefaults(
 14                         // 请求超时时间
 15                         HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(3000)
 16                 )
 17                 .andThreadPoolPropertiesDefaults(
 18                         // 定义Hystrix线程池中线程数量
 19                         HystrixThreadPoolProperties.Setter().withCoreSize(3)
 20                 )
 21         );
 22         this.name = name;
 23     }
 24 
 25     /**
 26      * 降级策略
 27      */
 28     @Override
 29     protected String getFallback() {
 30         System.out.println(Thread.currentThread() + "Hi This is Fallback for name:" + this.name);
 31         return this.name;
 32     }
 33 
 34     /**
 35      * 执行逻辑
 36      */
 37     @Override
 38     protected String run() throws Exception {
 39         TimeUnit.MILLISECONDS.sleep(800);
 40         System.out.println(Thread.currentThread() + " This is run in HystrixCommand , name :" + this.name);
 41         return name;
 42     }
 43 
 44     static class UnitTest {
 45 
 46         /**
 47          * 异步调用
 48          */
 49         @Test
 50         void testQueue() {
 51             System.out.println("Thread.currentThread(): " + Thread.currentThread());
 52             for (int i = 0; i < 5; i++) {
 53                 try {
 54                     Future<String> queue = new HystrixCommand4ThreadPool("thread" + i).queue();
 55                     System.out.println("thread" + i + "在干点其它的事...");
 56                     // queue.get -> 异步阻塞的获取执行结果
 57                     System.out.println("异步调用-获取结果:" + queue.get(1, TimeUnit.SECONDS));
 58                 }
 59                 catch (Exception e) {
 60                     e.printStackTrace();
 61                 }
 62             }
 63         }
 64 
 65         /**
 66          * 同步调用
 67          */
 68         @Test
 69         void testExecute() {
 70             System.out.println("Thread.currentThread(): " + Thread.currentThread());
 71             for (int i = 0; i < 5; i++) {
 72                 try {
 73                     String execute = new HystrixCommand4ThreadPool("thread" + i).execute();
 74                     System.out.println("同步调用-获取结果:" + execute);
 75                 }
 76                 catch (Exception e) {
 77                     e.printStackTrace();
 78                 }
 79             }
 80         }
 81 
 82         /**
 83          * 响应式调用
 84          */
 85         @Test
 86         void testObserve() {
 87             System.out.println("Thread.currentThread(): " + Thread.currentThread());
 88             for (int i = 0; i < 5; i++) {
 89                 try {
 90                     Observable<String> observe = new HystrixCommand4ThreadPool("thread" + i).observe();
 91                     System.out.println("哈哈哈,在等待响应嘛...");
 92                     observe.subscribe(result -> System.out.println("得到结果:" + result));
 93                 }
 94                 catch (Exception e) {
 95                     e.printStackTrace();
 96                 }
 97             }
 98 
 99             try {
100                 // 因testObserve是@Test,为守护线程,所以需要休眠等待执行结果
101                 TimeUnit.SECONDS.sleep(5L);
102             }
103             catch (InterruptedException e) {
104                 e.printStackTrace();
105             }
106         }
107 
108     }
109 
110 }

 

我们定义了一个类继承com.netflix.hystrix.HystrixCommand,因此此类便可以完成Hystrix一些基本功能,如线程池和信号量隔离等待。

在HystrixCommand4ThreadPool构造中,我们来初始化Hystrix,定义了Hystrix的线程组名称、命令名称、线程池名称以及超时时间核心线程数

获取结果的方式也分为三种:

  • 异步调用(异步阻塞式)。
  • 同步调用。
  • 响应式调用。

知识点:

  • getFallback():降级逻辑是运行在main线程中的,在无法获得核心线程时会从其它地方返回兜底数据(如redis等)。
  • 线程隔离的目的是管理线程资源,使线程资源不会滥用,可以保障服务节点的可用性。

2、线程隔离之信号量

信号量隔离其实和线程池隔离差不多,只是信号量隔离是内部的限流控制,当超过配置的信号量大小便会拒绝请求,从而达到限流保护的作用。

 1 public class HystrixCommand4Semaphore extends HystrixCommand<String> {
 2 
 3     private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
 4 
 5     private final String name;
 6 
 7     public HystrixCommand4Semaphore(String name) {
 8         super(Setter
 9                 .withGroupKey(HystrixCommandGroupKey.Factory.asKey("SemaphoreGroup"))
10                 .andCommandKey(HystrixCommandKey.Factory.asKey("SemaphoreKey"))
11                 .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("SemaphoreThreadPoolKey"))
12                 .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
13                         // 信号量隔离
14                         .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE)
15                         .withExecutionTimeoutInMilliseconds(3000)
16                         // 配置信号量大小
17                         .withExecutionIsolationSemaphoreMaxConcurrentRequests(3)
18                         // 配置降级并发量
19                         // .withFallbackIsolationSemaphoreMaxConcurrentRequests(1)
20                 )
21         );
22         this.name = name;
23     }
24 
25     @Override
26     protected String run() throws Exception {
27         System.out.println(sdf.format(new Date()) + "," + Thread.currentThread() + " This is run in HystrixCommand , name :" + this.name);
28         return this.name;
29     }
30 
31     @Override
32     protected String getFallback() {
33         System.out.println(sdf.format(new Date()) + "," + Thread.currentThread() + " Hi This is Fallback for name:" + this.name);
34         return this.name;
35     }
36 
37 
38     static class UnitTest {
39         @Test
40         void testHystrixCommand4Semaphore() {
41             for (int i = 0; i < 5; i++) {
42                 final int j = i;
43                 try {
44                     new Thread(() -> new HystrixCommand4Semaphore("Semaphore-Thread " + j).execute()).start();
45                 }
46                 catch (Exception e) {
47                     e.printStackTrace();
48                 }
49             }
50 
51             try {
52                 TimeUnit.SECONDS.sleep(5);
53             }
54             catch (InterruptedException e) {
55                 e.printStackTrace();
56             }
57         }
58     }
59 
60 }

知识点:

  • Semaphore隔离方式的运行时在main线程中,所以只支持同步调用方式。
  • Semaphore可以设置降级并发的线程数,.withFallbackIsolationSemaphoreMaxConcurrentRequests(int value)

3、线程池与信号量的比较

  线程池 信号量
线程 与调度线程非同一线程 与调度线程是同一线程
开销 排队、调度、上下文切换等开销 无线程切换,开销低
异步 支持 不支持

并发支持

支持(由线程池大小决定) 支持(由信号量大小决定)

 

 

 

 

 

 

 

 

服务降级:

当请求出现异常、超时、服务不可用等情况时,Hystrix可以自定义降级策略防止返回null或抛出异常

注意:

1、无限循环属于超时,会导致降级。

2、Hystrix降级就是用HystrixBadRequestException来处理的,所以抛出这个异常不会走降级。

demo:

 1 public class HystrixCommand4Fallback extends HystrixCommand<String> {
 2 
 3     private final String name;
 4 
 5     public HystrixCommand4Fallback(String name) {
 6         super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("FallbackGroup"))
 7                 // 超时时间1秒
 8                 .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(1000)));
 9         this.name = name;
10     }
11 
12     @Override
13     protected String getFallback() {
14         System.err.println(Thread.currentThread() + " Hi This is Fallback for name:" + this.name);
15         return this.name;
16     }
17 
18     @Override
19     protected String run() throws Exception {
20         // 1.无限循环,默认1秒钟超时。
21         while (true) {
22         }
23     }
24 
25 //    @Override
26 //    protected String run() throws Exception {
27 //        // 2.运行时异常
28 //        int i = 1 / 0;
29 //        return name;
30 //    }
31 
32 //    @Override
33 //    protected String run() throws Exception {
34 //        // 3.throw 异常
35 //        throw new Exception("xyz");
36 //    }
37 
38 //    @Override
39 //    protected String run() throws Exception {
40 //        // 4.HystrixBadRequestException异常不会触发降级
41 //        throw new HystrixBadRequestException("xtz");
42 //    }
43 
44     public static class UnitTest {
45         @Test
46         public void testHystrixCommand4Fallback() throws ExecutionException, InterruptedException {
47             System.out.println("--");
48             Future<String> threadFallback = new HystrixCommand4Fallback("Thread Fallback").queue();
49             threadFallback.get();
50         }
51     }
52 }

服务熔断:

熔断也叫做过载保护,它其实就是一个自我统计,统计啥呢?

在一段时间内请求成功和失败的次数,当失败次数达到阀值后,下次请求直接走fallback。一段时间后会尝试走正常流程,若成功的话后续流程便会走正常流程。

注意:

1、若在指定时间内没有达到请求数量,即使所有的请求失败了,也不会打开断路器

2、必须满足时间、请求数、失败比例三个条件才会触发断路器。

 1 public class HystrixCommand4CircuitBreaker extends HystrixCommand<String> {
 2     private final String name;
 3 
 4     protected HystrixCommand4CircuitBreaker(String name) {
 5         super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("circuitBreakerGroupKey"))
 6                 .andCommandKey(HystrixCommandKey.Factory.asKey("circuitBreakerKey"))
 7                 .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("circuitThreadPoolKey"))
 8                 .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(200))
 9                 .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withCircuitBreakerEnabled(true)
10                         // 10s内至少请求10次,如果10s内没有接收到10次请求,即使所有请求都失败了,断路器也不会打开
11                         .withMetricsRollingStatisticalWindowInMilliseconds(10000)
12                         .withCircuitBreakerRequestVolumeThreshold(10)
13                         // 当出错率超过50%后开启断路器.
14                         .withCircuitBreakerErrorThresholdPercentage(50)
15                         // 断路器打开后的休眠时间(当等待时间到达后才会开始统计)
16                         .withCircuitBreakerSleepWindowInMilliseconds(5000)));
17         this.name = name;
18     }
19 
20     @Override
21     protected String getFallback() {
22         System.out.println(Thread.currentThread() + "Hi This is Fallback for name:" + this.name);
23 //        // 当熔断后, fallback流程由main线程执行, 设置sleep, 体现熔断恢复现象.
24 //        try {
25 //            TimeUnit.MILLISECONDS.sleep(900);
26 //        } catch (InterruptedException e) {
27 //            e.printStackTrace();
28 //        }
29         return this.name;
30     }
31 
32     @Override
33     protected String run() throws Exception {
34         System.out.println("-----" + name);
35         int num = Integer.valueOf(name);
36 
37         // 模拟执行成功
38         if (num % 2 == 1) {
39             System.out.println("Hi This is HystrixCommand for name:" + this.name);
40             return name;
41         } else {
42             // 模拟异常
43             while (true) {
44             }
45         }
46     }
47 
48     public static class UnitTest {
49         @Test
50         public void testHystrixCommand4CircuitBreaker() {
51             final long start = System.currentTimeMillis();
52             for (int i = 0; i < 50; i++) {
53                 try {
54                     // queue() 异步调用 , execute() 同步调用
55                     new HystrixCommand4CircuitBreaker(i + "").execute();
56                 } catch (Exception e) {
57                     System.out.println("run 捕获异常 ");
58                     e.printStackTrace();
59                 }
60             }
61         }
62     }
63 }

运行后发现10秒内请求数量超时10个,且有一半以上失败时后续的请求才会走fallback。

然后我们再看第16行,我们设置了断路器执行时间,当断路器执行5秒后则会休眠继续重试正常流程;我们将23 - 28行注释打开便会发现断路器执行5秒后便会重试正常流程。

请求缓存:

Hystrix可以将请求的数据缓存起来,当后续有相同请求参数时会直接拿缓存的。这样可以避免了直接调用服务,从而减轻了服务器的压力。

Hystrix的请求缓存不常用,现在一般采用其它的缓存框架来实现,如redis,memoryCache。

 1 public class HystrixCommand4Cache extends HystrixCommand<Boolean> {
 2 
 3     private final int key;
 4     private final String value;
 5 
 6     protected HystrixCommand4Cache(int key, String value) {
 7         super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("CacheGroup")).andCommandPropertiesDefaults(
 8                 HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(1000)));
 9         this.key = key;
10         this.value = value;
11     }
12 
13     @Override
14     protected Boolean run() {
15         System.out.println("This is Run... ");
16         return true;
17     }
18 
19     @Override
20     protected String getCacheKey() {
21         // 构建cache的key;如果调用getCacheKey 得到的结果是相同的, 说明是相同的请求  可以走缓存
22         return key + value;
23     }
24 
25     @Override
26     protected Boolean getFallback() {
27         System.err.println("fallback");
28         return false;
29     }
30 
31     public static class UnitTest {
32         @Test
33         public void testHystrixCommand4Cache() {
34             //同一个请求上下文中
35             HystrixRequestContext.initializeContext();
36             HystrixCommand4Cache command2a = new HystrixCommand4Cache(2, "HystrixCommand4RequestCacheTest");
37             HystrixCommand4Cache command2b = new HystrixCommand4Cache(2, "HystrixCommand4RequestCacheTest");
38             HystrixCommand4Cache command2c = new HystrixCommand4Cache(2, "NotCache");
39             System.out.println("command2a:" + command2a.execute());
40             // 第一次请求,不可能命中缓存
41             System.err.println("第1次请求是否命中缓存:" + command2a.isResponseFromCache());
42             System.out.println("command2b:" + command2b.execute());
43             // 命中缓存
44             System.err.println("第2次请求是否命中缓存:" + command2b.isResponseFromCache());
45             System.out.println("command2c:" + command2c.execute());
46             //未命中缓存
47             System.err.println("第3次请求是否命中缓存:" + command2c.isResponseFromCache());
48 
49             // 开启一个新的请求,会重新获取一个新的上下文(清空缓存)
50             HystrixRequestContext.initializeContext();
51             HystrixCommand4Cache command3a = new HystrixCommand4Cache(2, "HystrixCommand4RequestCacheTest");
52             HystrixCommand4Cache command3b = new HystrixCommand4Cache(2, "HystrixCommand4RequestCacheTest");
53             System.out.println("command3a:" + command3a.execute());
54             // 新的请求上下文中不会命中上一个请求中的缓存
55             System.err.println("第4次请求是否命中缓存:" + command3a.isResponseFromCache());
56             // 从新的请求上下文中command3a.execute()执行中得到的cache
57             System.out.println("command3b:" + command3b.execute());
58             System.err.println("第5次请求是否命中缓存:" + command3b.isResponseFromCache());
59         }
60     }
61 }

注意:

  • 判断是否走请求缓存的依据是,参数是否相同。
  • HystrixRequestContext.initializeContext()开启请求上下文,且只有在同一个上下文中请求才会获取缓存。

请求合并:

同意的Hystrix可以将相同类型的请求合并,而不是分别调用服务提供方,这样可以减少服务端的压力。

1、首先拿到一段时间类类似的请求。

  • localhost:8080/order/1
  • localhost:8080/order/2
  • localhost:8080/order/3

2、从getRequestArgument()获得key,然后合并。

3、绑定不同请求与结果的关系。

 1 public class HystrixCommand4Collapser extends HystrixCollapser<List<String>, String, Integer> {
 2 
 3     private final Integer key;
 4 
 5     public HystrixCommand4Collapser(Integer key) {
 6         this.key = key;
 7     }
 8 
 9     @Override
10     public Integer getRequestArgument() {
11         return key;
12     }
13 
14     /**
15      * 创建一个批量请求命令
16      */
17     @Override
18     protected HystrixCommand<List<String>> createCommand(Collection<CollapsedRequest<String, Integer>> requests) {
19         System.out.println("createCommand request size " + requests.size());
20         // 调用HystrixCommand实现类,构建Collapser命令
21         return new BatchCommand(requests);
22     }
23 
24     /**
25      * 将批量请求的结果和对应的请求一一对应
26      */
27     @Override
28     protected void mapResponseToRequests(List<String> batchResponse, Collection<CollapsedRequest<String, Integer>> requests) {
29         int count = 0;
30         System.out.println("mapResponseToRequests request size " + requests.size() + ", and batchResponse size " + batchResponse.size());
31         for (CollapsedRequest<String, Integer> request : requests) {
32             request.setResponse(batchResponse.get(count++));
33         }
34     }
35 
36     private static final class BatchCommand extends HystrixCommand<List<String>> {
37 
38         private final Collection<CollapsedRequest<String, Integer>> requests;
39 
40         public BatchCommand(Collection<CollapsedRequest<String, Integer>> requests) {
41             super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("BatchCommandGroupKey"))
42                     .andCommandKey(HystrixCommandKey.Factory.asKey("BatchCommandKey")));
43             this.requests = requests;
44         }
45 
46         @Override
47         protected List<String> run() throws Exception {
48             ArrayList<String> responseList = new ArrayList<>();
49             // 处理每个请求,返回结果
50             for (CollapsedRequest<String, Integer> request : requests) {
51                 // 模拟一个response
52                 String response = "ValueForKey: " + request.getArgument() + " thread:" + Thread.currentThread().getName();
53                 responseList.add(response);
54             }
55             System.out.println("responseListSize:" + responseList.size());
56             return responseList;
57         }
58     }
59 
60     static class UnitTest {
61         @Test
62         void testHystrix4Collapser() throws Exception {
63             HystrixRequestContext context = HystrixRequestContext.initializeContext();
64             try {
65                 Future<String> f1 = new HystrixCommand4Collapser(1).queue();
66                 Future<String> f2 = new HystrixCommand4Collapser(2).queue();
67                 Future<String> f3 = new HystrixCommand4Collapser(3).queue();
68                 TimeUnit.MILLISECONDS.sleep(10);
69                 Future<String> f4 = new HystrixCommand4Collapser(4).queue();
70 
71                 System.out.println(System.currentTimeMillis() + " : " + f1.get());
72                 System.out.println(System.currentTimeMillis() + " : " + f2.get());
73                 System.out.println(System.currentTimeMillis() + " : " + f3.get());
74                 System.out.println(System.currentTimeMillis() + " : " + f4.get());
75                 // 下面3条都不在一个批量请求中
76                 System.out.println(new HystrixCommand4Collapser(5).execute());
77                 System.out.println(new HystrixCommand4Collapser(6).queue().get());
78                 System.out.println(new HystrixCommand4Collapser(7).queue().get());
79             }
80             finally {
81                 context.shutdown();
82             }
83         }
84     }
85     
86 }

知识点:

  • 调用queue()发起请求,会将毫秒级之内的请求进行合并
  • 首先,调用createCommand()创建批量命令。
  • 然后,调用HystrixCommand实现类具体构建命令,并执行该线程。
  • 最后,通过mapResponseToRequests构建批量的响应结果。

Hystrix流程:

1、每次调用创建一个新的HystrixCommand,其执行逻辑都在run()方法中。

2、通过执行execute()或queue()方法做同步或异步的调用(底层都是通过toObservable()来完成具体调用)。

3、判断是否有请求缓存,有则用缓存。

4、判断熔断器是否打开,打开则见8,进行降级。

5、判断线程池或信号量是否已满,若已满则见8,进行降级。

6、调用HystrixObservableCommand.construct()或HystrixCommand.run()执行具体逻辑。

  • 若逻辑执行有误,见8。
  • 若逻辑调用超时,见8。

7、计算熔断器状态及所有的运行状态(成功、失败、拒绝、超时),并上报给熔断器,此操作用于熔断器的判断状态。

8、调用getFallback()方法执行降级逻辑;触发getFallback()方法的条件如下:

  • run()方法抛出非HystrixBadRequestException异常。
  • run()方法超时。
  • 熔断器开启。
  • 线程池或信号量已满。

9、返回执行结果。

Hystrix属性:

1、CommandProperties

2、ThreadPoolProperties

注解方式实现Hystrix:

 1 @GetMapping("/testThread")
 2 @HystrixCommand(
 3         groupKey = "ThreadPoolGroupKey",
 4         commandKey = "ThreadPoolCommandKey",
 5         threadPoolKey = "ThreadPoolKey",
 6         fallbackMethod = "fallbackMethod",
 7         commandProperties = {
 8                 @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000"),
 9                 @HystrixProperty(name = "execution.timeout.enabled", value = "true"),
10                 @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD")
11         },
12         threadPoolProperties = {
13                 @HystrixProperty(name = "coreSize", value = "15")
14         }
15 )
16 public String testThread() {
17     return "Thread Pool";
18 }

Hystrix Dashboard:

Hystrix Dashboard是一款图形化的Hystrix服务信息工具。

它的使用方式很简单:

1、创建HystrixDashboard项目

2、增加依赖

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

3、启动类上增加@EnableHystrixDashboard注解

以上是单机Hystrix的监控方法,如果是Hystrix集群的话还需要依赖turbine:

1、首先将所有结点及HystrixDashboard注册到eureka

2、Hystrix添加依赖

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

3、启动类加上@EnableTurbine

4、配置properties

eureka.client.serviceUrl.defaultZone=http://localhost:9091/eureka
## 配置Turbine管理端服务名称
turbine.app-config=helloServer,helloServer
## 默认集群名称
turbine.cluster-name-expression=new String("default")

 

posted @ 2019-10-12 14:50  被猪附身的人  阅读(312)  评论(0编辑  收藏  举报