1. 程式人生 > 實用技巧 >Hystrix斷路器的基本使用

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()+"\t"+ "呼叫成功,流水號:" + 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

主頁面

這裡我們演示監控 服務提供方服務,

在被監控的專案中 新增一個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

就會進入如下介面(監控前 服務端最好有被呼叫過,不然會一直顯示Loading):

此頁面具體使用規則這裡不做記錄