SpringCloud Hystrix断路器的基本使用

官网资料: https://github.com/Netflix/Hystrix/wiki/How-To-Use

1. 服务雪崩

分布式系统面临的问题

  • 复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免的因为各种因素通信失败

  • 多个微服务之间调用的时候,如果调用链过长,那么链路上的其中某个微服务因为响应时间过长或者不可用,对整个链路上的所有的微服务都产生影响,引起系统雪崩效应

  • 对于高流量应用来说,如果某个微服务因为不可用或者响应时间长,导致整体服务延迟增加,队列堆积,线程和其他资源紧张 ,导致系统发生级联故障. 我们应该将故障进行隔离,降级,

2. 功能介绍

Hystrix断路器 的目的则是解决上述问题的工具,通过服务降级,服务熔断,服务限流等手段对 故障的服务进行管控

  • 服务降级:
    当程序运行异常,超时,线程池/信号量打满 等 将会导致服务降级,可以给用户一个友好的提示 例如服务器忙,请稍候再试,不让客户端等待并立刻返回一个友好提示,而不是抛出异常

  • 服务熔断:
    类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示

  • 服务限流:
    高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行

3. 问题重现

服务提供方,注册eureka

hystrix 相关依赖:

<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

yaml:

server:
  port: 8001

eureka:
  client:
    register-with-eureka: true   #是否将自己注册到注册中心,集群必须设置为true配合ribbon
    fetch-registry: true    #是否从服务端抓取已有的注册信息
    service-url:
      defaultZone: http://127.0.0.1.com:7001/eureka

spring:
  application:
    name: cloud-provider-hystrix-payment

主启动类: 启用Hystrix 自动配置

@SpringBootApplication
@EnableHystrix
public class PaymentMain8001 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain8001.class,args);
    }
}

服务提供方Controller 简单调用Service层方法

@RestController
@Slf4j
public class PaymentController {

    @Resource
    private PaymentService paymentService;

	/*
	* 调用Service的paymentInfo_OK方法
	*/
    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id) {
        return paymentService.paymentInfo_OK(id);
    }
    
    /*
    * 被除数为0, 模拟出错场景
    */
    @GetMapping("/payment/hystrix/error/{id}")
    public String paymentInfo_Error(@PathVariable("id") Integer id) {
        return paymentService.paymentInfo_Error(id);
    }
    
	/*
	* 调用Service的paymentService.paymentInfo_TimeOut 长时间服务接口
	*/
    @GetMapping("/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id) {
        return paymentService.paymentInfo_TimeOut(id);
    }

}

这里paymentInfo_TimeOut 接口是一个 长时间的调用, 而paymentInfo_OK 是一个非常正常的接口,但是如果这时我用测试工具 强压 paymentInfo_TimeOut 接口 导致线程数被沾满,也将影响到正常情况下调用非常快速的其他接口, 这也就是我们需要解决的问题

4. 服务熔断和降级

4.1 服务降级

使用Hystrix提供的注解,对抛出异常的方法进行降级,@HystrixCommand 并指定 降级方法

@Service
public class PaymentService {
    /**
     * 正常访问,肯定ok
     *
     * @param id
     * @return
     */
    public String paymentInfo_OK(Integer id) {
        return "调用正常";
    }

    /**
    *  抛出异常 调用fallbackMethod 定义的兜底方法
    */
    @HystrixCommand(fallbackMethod = "paymentInfo_ErrorHandler")
    public String paymentInfo_Error(Integer id) {

        int i = 10/0;
        return "调用成功"+id;
    }

    public String paymentInfo_ErrorHandler(Integer id) {
        return "系统错误"+id;
    }

浏览器访问 该接口:http://127.0.0.1:8001/payment/hystrix/error/10

返回信息: 系统错误10 接口出错,调用fallback方法 并将参数传递过去

4.2 自定义规则

上面的例子中没有指定任何 规则,默认方法报错为降级条件, Hystrix 提供了丰富的降级规则制定,

所有的规则都在com.netflix.hystrix.HystrixCommandProperties 类中定义


/**
 * Properties for instances of {@link HystrixCommand}.
 * <p>
 * Default implementation of methods uses Archaius (https://github.com/Netflix/archaius)
 */
public abstract class HystrixCommandProperties {
    private static final Logger logger = LoggerFactory.getLogger(HystrixCommandProperties.class);

    /* 重要参数的默认值配置 */
    
    /* package */ static final Integer default_metricsRollingStatisticalWindow = 10000;// default => statisticalWindow: 10000 = 10 seconds (and default of 10 buckets so each bucket is 1 second)
    private static final Integer default_metricsRollingStatisticalWindowBuckets = 10;// default => statisticalWindowBuckets: 10 = 10 buckets in a 10 second window so each bucket is 1 second
    private static final Integer default_circuitBreakerRequestVolumeThreshold = 20;// default => statisticalWindowVolumeThreshold: 20 requests in 10 seconds must occur before statistics matter
    private static final Integer default_circuitBreakerSleepWindowInMilliseconds = 5000;// default => sleepWindow: 5000 = 5 seconds that we will sleep before trying again after tripping the circuit
    private static final Integer default_circuitBreakerErrorThresholdPercentage = 50;// default => errorThresholdPercentage = 50 = if 50%+ of requests in 10 seconds are failures or latent then we will trip the circuit
    private static final Boolean default_circuitBreakerForceOpen = false;// default => forceCircuitOpen = false (we want to allow traffic)
    /* package */ static final Boolean default_circuitBreakerForceClosed = false;// default => ignoreErrors = false 
    private static final Integer default_executionTimeoutInMilliseconds = 1000; // default => executionTimeoutInMilliseconds: 1000 = 1 second
    private static final Boolean default_executionTimeoutEnabled = true;
    private static final ExecutionIsolationStrategy default_executionIsolationStrategy = ExecutionIsolationStrategy.THREAD;
    private static final Boolean default_executionIsolationThreadInterruptOnTimeout = true;
    private static final Boolean default_executionIsolationThreadInterruptOnFutureCancel = false;
    private static final Boolean default_metricsRollingPercentileEnabled = true;
    private static final Boolean default_requestCacheEnabled = true;
    private static final Integer default_fallbackIsolationSemaphoreMaxConcurrentRequests = 10;
    private static final Boolean default_fallbackEnabled = true;
    private static final Integer default_executionIsolationSemaphoreMaxConcurrentRequests = 10;
    private static final Boolean default_requestLogEnabled = true;
    private static final Boolean default_circuitBreakerEnabled = true;
    private static final Integer default_metricsRollingPercentileWindow = 60000; // default to 1 minute for RollingPercentile 
    private static final Integer default_metricsRollingPercentileWindowBuckets = 6; // default to 6 buckets (10 seconds each in 60 second window)
    private static final Integer default_metricsRollingPercentileBucketSize = 100; // default to 100 values max per bucket
    private static final Integer default_metricsHealthSnapshotIntervalInMilliseconds = 500; // default to 500ms as max frequency between allowing snapshots of health (error percentage etc)

    /**
    * 保存每个配置的 参数定义
    */
    @SuppressWarnings("unused") private final HystrixCommandKey key;
    private final HystrixProperty<Integer> circuitBreakerRequestVolumeThreshold; // number of requests that must be made within a statisticalWindow before open/close decisions are made using stats
    private final HystrixProperty<Integer> circuitBreakerSleepWindowInMilliseconds; // milliseconds after tripping circuit before allowing retry
    private final HystrixProperty<Boolean> circuitBreakerEnabled; // Whether circuit breaker should be enabled.
    private final HystrixProperty<Integer> circuitBreakerErrorThresholdPercentage; // % of 'marks' that must be failed to trip the circuit
    private final HystrixProperty<Boolean> circuitBreakerForceOpen; // a property to allow forcing the circuit open (stopping all requests)
    private final HystrixProperty<Boolean> circuitBreakerForceClosed; // a property to allow ignoring errors and therefore never trip 'open' (ie. allow all traffic through)
    private final HystrixProperty<ExecutionIsolationStrategy> executionIsolationStrategy; // Whether a command should be executed in a separate thread or not.
    private final HystrixProperty<Integer> executionTimeoutInMilliseconds; // Timeout value in milliseconds for a command
    private final HystrixProperty<Boolean> executionTimeoutEnabled; //Whether timeout should be triggered
    private final HystrixProperty<String> executionIsolationThreadPoolKeyOverride; // What thread-pool this command should run in (if running on a separate thread).
    private final HystrixProperty<Integer> executionIsolationSemaphoreMaxConcurrentRequests; // Number of permits for execution semaphore
    private final HystrixProperty<Integer> fallbackIsolationSemaphoreMaxConcurrentRequests; // Number of permits for fallback semaphore
    private final HystrixProperty<Boolean> fallbackEnabled; // Whether fallback should be attempted.
    private final HystrixProperty<Boolean> executionIsolationThreadInterruptOnTimeout; // Whether an underlying Future/Thread (when runInSeparateThread == true) should be interrupted after a timeout
    private final HystrixProperty<Boolean> executionIsolationThreadInterruptOnFutureCancel; // Whether canceling an underlying Future/Thread (when runInSeparateThread == true) should interrupt the execution thread
    private final HystrixProperty<Integer> metricsRollingStatisticalWindowInMilliseconds; // milliseconds back that will be tracked
    private final HystrixProperty<Integer> metricsRollingStatisticalWindowBuckets; // number of buckets in the statisticalWindow
    private final HystrixProperty<Boolean> metricsRollingPercentileEnabled; // Whether monitoring should be enabled (SLA and Tracers).
    private final HystrixProperty<Integer> metricsRollingPercentileWindowInMilliseconds; // number of milliseconds that will be tracked in RollingPercentile
    private final HystrixProperty<Integer> metricsRollingPercentileWindowBuckets; // number of buckets percentileWindow will be divided into
    private final HystrixProperty<Integer> metricsRollingPercentileBucketSize; // how many values will be stored in each percentileWindowBucket
    private final HystrixProperty<Integer> metricsHealthSnapshotIntervalInMilliseconds; // time between health snapshots
    private final HystrixProperty<Boolean> requestLogEnabled; // whether command request logging is enabled.
    private final HystrixProperty<Boolean> requestCacheEnabled; // Whether request caching is enabled.

  

    //将默认值初始化
    protected HystrixCommandProperties(HystrixCommandKey key, HystrixCommandProperties.Setter builder, String propertyPrefix) {
        this.key = key;
        this.circuitBreakerEnabled = getProperty(propertyPrefix, key, "circuitBreaker.enabled", builder.getCircuitBreakerEnabled(), default_circuitBreakerEnabled);
        this.circuitBreakerRequestVolumeThreshold = getProperty(propertyPrefix, key, "circuitBreaker.requestVolumeThreshold", builder.getCircuitBreakerRequestVolumeThreshold(), default_circuitBreakerRequestVolumeThreshold);
        this.circuitBreakerSleepWindowInMilliseconds = getProperty(propertyPrefix, key, "circuitBreaker.sleepWindowInMilliseconds", builder.getCircuitBreakerSleepWindowInMilliseconds(), default_circuitBreakerSleepWindowInMilliseconds);
        this.circuitBreakerErrorThresholdPercentage = getProperty(propertyPrefix, key, "circuitBreaker.errorThresholdPercentage", builder.getCircuitBreakerErrorThresholdPercentage(), default_circuitBreakerErrorThresholdPercentage);
        this.circuitBreakerForceOpen = getProperty(propertyPrefix, key, "circuitBreaker.forceOpen", builder.getCircuitBreakerForceOpen(), default_circuitBreakerForceOpen);
        this.circuitBreakerForceClosed = getProperty(propertyPrefix, key, "circuitBreaker.forceClosed", builder.getCircuitBreakerForceClosed(), default_circuitBreakerForceClosed);
        this.executionIsolationStrategy = getProperty(propertyPrefix, key, "execution.isolation.strategy", builder.getExecutionIsolationStrategy(), default_executionIsolationStrategy);
        //this property name is now misleading.  //TODO figure out a good way to deprecate this property name
        this.executionTimeoutInMilliseconds = getProperty(propertyPrefix, key, "execution.isolation.thread.timeoutInMilliseconds", builder.getExecutionIsolationThreadTimeoutInMilliseconds(), default_executionTimeoutInMilliseconds);
        this.executionTimeoutEnabled = getProperty(propertyPrefix, key, "execution.timeout.enabled", builder.getExecutionTimeoutEnabled(), default_executionTimeoutEnabled);
        this.executionIsolationThreadInterruptOnTimeout = getProperty(propertyPrefix, key, "execution.isolation.thread.interruptOnTimeout", builder.getExecutionIsolationThreadInterruptOnTimeout(), default_executionIsolationThreadInterruptOnTimeout);
        this.executionIsolationThreadInterruptOnFutureCancel = getProperty(propertyPrefix, key, "execution.isolation.thread.interruptOnFutureCancel", builder.getExecutionIsolationThreadInterruptOnFutureCancel(), default_executionIsolationThreadInterruptOnFutureCancel);
        this.executionIsolationSemaphoreMaxConcurrentRequests = getProperty(propertyPrefix, key, "execution.isolation.semaphore.maxConcurrentRequests", builder.getExecutionIsolationSemaphoreMaxConcurrentRequests(), default_executionIsolationSemaphoreMaxConcurrentRequests);
        this.fallbackIsolationSemaphoreMaxConcurrentRequests = getProperty(propertyPrefix, key, "fallback.isolation.semaphore.maxConcurrentRequests", builder.getFallbackIsolationSemaphoreMaxConcurrentRequests(), default_fallbackIsolationSemaphoreMaxConcurrentRequests);
        this.fallbackEnabled = getProperty(propertyPrefix, key, "fallback.enabled", builder.getFallbackEnabled(), default_fallbackEnabled);
        this.metricsRollingStatisticalWindowInMilliseconds = getProperty(propertyPrefix, key, "metrics.rollingStats.timeInMilliseconds", builder.getMetricsRollingStatisticalWindowInMilliseconds(), default_metricsRollingStatisticalWindow);
        this.metricsRollingStatisticalWindowBuckets = getProperty(propertyPrefix, key, "metrics.rollingStats.numBuckets", builder.getMetricsRollingStatisticalWindowBuckets(), default_metricsRollingStatisticalWindowBuckets);
        this.metricsRollingPercentileEnabled = getProperty(propertyPrefix, key, "metrics.rollingPercentile.enabled", builder.getMetricsRollingPercentileEnabled(), default_metricsRollingPercentileEnabled);
        this.metricsRollingPercentileWindowInMilliseconds = getProperty(propertyPrefix, key, "metrics.rollingPercentile.timeInMilliseconds", builder.getMetricsRollingPercentileWindowInMilliseconds(), default_metricsRollingPercentileWindow);
        this.metricsRollingPercentileWindowBuckets = getProperty(propertyPrefix, key, "metrics.rollingPercentile.numBuckets", builder.getMetricsRollingPercentileWindowBuckets(), default_metricsRollingPercentileWindowBuckets);
        this.metricsRollingPercentileBucketSize = getProperty(propertyPrefix, key, "metrics.rollingPercentile.bucketSize", builder.getMetricsRollingPercentileBucketSize(), default_metricsRollingPercentileBucketSize);
        this.metricsHealthSnapshotIntervalInMilliseconds = getProperty(propertyPrefix, key, "metrics.healthSnapshot.intervalInMilliseconds", builder.getMetricsHealthSnapshotIntervalInMilliseconds(), default_metricsHealthSnapshotIntervalInMilliseconds);
        this.requestCacheEnabled = getProperty(propertyPrefix, key, "requestCache.enabled", builder.getRequestCacheEnabled(), default_requestCacheEnabled);
        this.requestLogEnabled = getProperty(propertyPrefix, key, "requestLog.enabled", builder.getRequestLogEnabled(), default_requestLogEnabled);
      
 
}

下面的例子中使用了超时时间的配置

@Service
public class PaymentService {
   
    public String paymentInfo_OK(Integer id) {
        return "调用正常";
    }

    /**
    * Hystrix 的注解, 用于定义该接口的各种规则 
    * paymentInfo_TimeOutHandler 定义fallback
    * execution.isolation.thread.timeoutInMilliseconds 为本接口最大访问时间为 2000 毫秒
    */
    @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
    })
    public String paymentInfo_TimeOut(Integer id) {

        try {
            TimeUnit.MILLISECONDS.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "长流程调用成功"+id;
    }

    /*
    * 超时降级方法 
    */
    public String paymentInfo_TimeOutHandler(Integer id) {
        return "系统繁忙系统报错,请稍后再试"+id;
    }
}

该案例中,该接口的访问时间为 3秒钟,定义的规则为 超时2秒则调用fallback ,

调用接口 http://127.0.0.1:8001/payment/hystrix/timeout/10

返回 系统繁忙系统报错,请稍后再试10 很显然 ,进入了超时方法,并将参数也传了过去

4.3 服务熔断

前面的降级操作,每个请求仍然是接受并处理的,只是在超时或者报错时进行降级

那如果在一定时间内,确定这个服务都不可用,就可以使某个接口熔断,所以请求皆不可用 ,更加减轻服务器压力, 在一定时间后再恢复过来

仍然是在@HystrixCommand 中定义熔断的规则,基本的使用请看下面的代码注释

//***************** 服务熔断***********************

    //该案例的意思是 5000毫秒内 十次请求 有百分之60失败 则熔断10 秒钟,10秒后尝试恢复
    @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties ={
            @HystrixProperty(name = "circuitBreaker.enabled",value = "true"), //是否开启断路器
        	@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value = "5000"), //统计窗口时间
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"), //统计窗口时间内最少请求次数
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), //短路多久以后开始尝试是否恢复,默认5s
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),//失败率达到多少后跳闸
    })
    public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
        if (id < 0) {
            throw new RuntimeException("******id 不能为负数");
        }
        String serialNumber = IdUtil.simpleUUID();
        return Thread.currentThread().getName()+"	"+ "调用成功,流水号:" + serialNumber;
    }

    public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id) {
        return "id 不能负数,请稍后再试,id:" + id;
    }

此案例的代码的意思就是 : 开启服务熔断功能,并指定 在5秒时间内至少有10次请求,并当错误率达到60% 以上时,将熔断此接口,拒绝一切请求,并在10 秒后开始尝试恢复正常,如果没有错误 就完全恢复

测试: 方法中定义如果接收负数则视为出错,正数则为正常,

调用接口 分别传入 -10 和 10 一次调用失败,抛出错误 调用 fallback方法,一次调用成功,返回服务端端口

熔断: 快速调用错误方式,使其达到熔断条件 5秒内 访问次数达到10次,错误率超过 60% ,此时 该接口熔断,及时传入正数的正确方式,也是进入 fallback方法, 拒绝了一切请求,当 10秒后 ,会尝试接收请求,如果 是正确的 则正式恢复,如果仍然检测出错误请求,则继续熔断

5. 统一调用方法

在上面的案例中,每个方法指定了其fallback方法, 定义了 其 出错时的 兜底方法,但是如果 配置过多,每个都配置一个方法,那么项目中将存在大量的冗余代码,对于相似的错误 可以使用 默认的处理方法 统一处理

@DefaultProperties(defaultFallback 定义在类上 ,定义此类中方法默认的fallback 方法

示例:

@Service
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public class PaymentService {
   
    public String paymentInfo_OK(Integer id) {
        return "调用正常";
    }
    
    @HystrixCommand
    public String paymentInfo_Error(Integer id) {
        int i = 10/0;
        return "调用成功"+id;
    }

    @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
    })
    public String paymentInfo_TimeOut(Integer id) {

        try {
            TimeUnit.MILLISECONDS.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "长流程调用成功"+id;
    }
    
    /*
    * 超时降级方法 
    */
    public String paymentInfo_TimeOutHandler(Integer id) {
        return "系统繁忙系统报错,请稍后再试"+id;
    }

    /*
    * 全局fallback
    */
    public String payment_Global_FallbackMethod() {
        return "系统繁忙系统报错,请稍后再试";
    }
}

上面三个方法中, 具体使用哪个规则,哪个兜底方法

  • 第一个 没有加任何注解,没有将此接口交给 Hystrix 管控,所以即使此方法出错 也不会被降级,将会非常普通的直接抛出异常

  • 第二个方法,使用基本的注解 但是没有使用规则也没有指定对应的 fallback方法,所以当方法内报错时,将会进入类上指定的默认fallback方法

  • 第三个方法 指定规则为超时 并指定 单独的fallback 所以当内部报错 或者 方法调用超时时,将会进入该方法指定的fallback方法

6. Feign 对 Hystrix的支持

在上面的案例中,我们的异常处理 都是在 server 端 是 sever端自己对自己的降级保护,但是 在实际环境中,如果服务端宕机或死掉,那么我们配置的这些 将起不到作用,调用方仍然将可能会出现异常,超时等,所以一般在服务调用方中也会进行保护

使用方法和上面一样,可以在controller 或者 service 上添加配置

若调用方使用 OpenFeign 调用 服务,也可以使用 Feign中自带的支持Hystrix方式

示例:

OpenFeign 调用接口,指定 fallback 类,此类实现该接口,当对应的方法错误,或超时时,会调用fallback类中对应的降级方法


@Component
//Feign对 Hystrix的支持 , fallback 指定 如果出错调用的类
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class)
public interface PaymentHystrixService {

    @GetMapping("/payment/hystrix/ok/{id}")
    String paymentInfo_OK(@PathVariable("id") Integer id);

    @GetMapping("/payment/hystrix/timeout/{id}")
    String paymentInfo_TimeOut(@PathVariable("id") Integer id);

}

fallback 类 实现 Feign接口

@Component
public class PaymentFallbackService implements  PaymentHystrixService{
    @Override
    public String paymentInfo_OK(Integer id) {
        return "-------PaymentFallbackService fall back-paymentInfo_OK,o(╥﹏╥)o";
    }

    @Override
    public String paymentInfo_TimeOut(Integer id) {
        return "-------PaymentFallbackService fall back-paymentInfo_TimeOut,o(╥﹏╥)o";
    }
}

application 配置中开启 feign对Hystrix 的支持

# feign 对 hystrix 的支持
feign:
  hystrix:
    enabled: true

7. Hystrix 服务监控可视化页面

Hystrix 还提供了准实时的调用监控页面,会持续记录所有通过Hystrix 发起的请求的执行信息,并通过统计报表和图形的形式展示给用户

需要搭建一个服务监控平台

依赖:

 <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

yaml 指定监控地址的端口

server:
  port: 9001

主启动类,开启

@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardMain9001 {
    public static void main(String[] args) {
        SpringApplication.run(HystrixDashboardMain9001.class, args);
    }
}

启动项目 浏览器访问:http://127.0.0.1:9001/hystrix

主页面

SpringCloud Hystrix断路器的基本使用

这里我们演示监控 服务提供方服务,

在被监控的项目中 添加一个bean ,解决 新版 Hystrix 的一个坑, 如果出现 Unable to connect to Command Metric Stream 或者 404 等错误 可以加上试试

@SpringBootApplication
@EnableEurekaClient
@EnableHystrix
public class PaymentMain8001 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain8001.class,args);
    }

    /**
     * 此配置是为了服务监控而配置,与服务器容错本身无关,springcloud升级后的坑
     * ServletRegistrationBean因为springboot的默认路径不是/hystrix.stream
     * 只要在自己的项目里配置上下文的servlet就可以了
     */
    @Bean
    public ServletRegistrationBean getservlet(){
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean<HystrixMetricsStreamServlet> registrationBean = new ServletRegistrationBean<>(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }
}

其他不用修改 启动项目

输入被监控服务的数据url : http://127.0.0.1:8001/hystrix.stream

SpringCloud Hystrix断路器的基本使用

就会进入如下界面(监控前 服务端最好有被调用过,不然会一直显示Loading):

SpringCloud Hystrix断路器的基本使用

此页面具体使用规则这里不做记录