SpringCloud系列第06節之斷路器Hystrix

前言

微服務架構中,通常都存在着不少的服務單元html

這樣就有可能出現一個單元由於網絡緣由或自身問題而出現故障或延遲,致使調用方的對外服務也出現延遲java

若是此時調用方的請求不斷增長,時間一長就會出現因爲等待故障方響應而造成任務積壓,最終致使調用方自身服務的癱瘓git

爲了解決這種問題:便出現了斷路器(或者叫熔斷器,Cricuit Breaker)模式github

斷路器模式源於 Martin Fowler 的 Circuit Breaker 一文web

咱們平常生活中的斷路器,自己是一種開關裝置,用於在電路上保護線路過載spring

當線路中有電器發生短路時,它可以及時切斷故障電路,防止發生過載、發熱、甚至起火等嚴重後果apache

而微服務架構中的斷路器,其做用是:當某個服務單元發生故障(相似用電器短路)以後網絡

經過斷路器的故障監控(相似熔斷保險絲),向調用方返回一個錯誤響應,而不是長時間的等待架構

這就不會使得線程被故障服務長時間佔用而不釋放,避免了故障在分佈式系統中的蔓延併發

Hystrix的介紹

Hystrix 正是 Netflix 開源的 javanica 提供的微服務框架套件之一

它是由 Java 實現的,用來處理分佈式系統發生故障或延遲時的容錯庫

它提供了 斷路器、資源隔離、自我修復 三大功能

  1. 斷路器
    實際可初步理解爲快速失敗,快速失敗是防止資源耗盡的關鍵點
    當 Hystrix 發如今過去某段時間內對服務 AA 的調用出錯率達到閥值時,它就會「熔斷」該服務
    後續任何向服務 AA 的請求都會快速失敗,而不是白白讓調用線程去等待
  2. 資源隔離
    首先,Hystrix 對每個依賴服務都配置了一個線程池,對依賴服務的調用會在線程池中執行
    好比,服務 AA 的線程池大小爲20,那麼 Hystrix 會最多容許有20個容器線程調用服務 AA(超出20,它會拒絕並快速失敗)
    這樣即便服務 AA 長時間未響應,容器最多也只能堵塞20個線程,剩餘的線程仍然能夠處理用戶請求
  3. 自我修復
    處於熔斷狀態的服務,在通過一段時間後,Hystrix 會讓其進入「半關閉」狀態(即容許少許請求經過)
    而後統計調用的成功率,若每一個請求都能成功,Hystrix 會恢復該服務,從而達到自我修復的效果
    其中:在服務被熔斷到進入「半關閉」狀態之間的時間,就是留給開發人員排查錯誤並恢復故障的時間

Hystrix的隔離策略

Hystrix 基於命令模式 HystrixCommand 來包裝依賴調用邏輯,其每一個命令在單獨線程中或信號受權下執行

(Command 是在 Receiver 和 Invoker 之間添加的中間層,Command 實現了對 Receiver 的封裝)

Hystrix 支持兩種隔離策略:線程池隔離和信號量隔離(都是限制對共享資源的併發訪問量)

  1. ThreadPool
    根據配置把不一樣命令分配到不一樣的線程池中,這是比較經常使用的隔離策略,其優勢是隔離性好,而且能夠配置斷路
    某個依賴被設置斷路以後,系統不會再嘗試新起線程運行它,而是直接提示失敗,或返回fallback值
    它的缺點是新起線程執行命令,在執行時必然涉及上下文的切換,這會形成必定的性能消耗
    可是 Netflix 作過實驗,這種消耗對比其帶來的價值是徹底能夠接受的,具體的數據參見 Hystrix-Wiki
  2. Semaphores
    顧名思義就是使用一個信號量來作隔離
    開發者能夠限制系統對某一個依賴的最高併發數,這個基本上就是一個限流的策略
    每次調用依賴時都會檢查一下是否到達信號量的限制值,如達到,則拒絕
    該策略的優勢是不新起線程執行命令,減小上下文切換,缺點是沒法配置斷路,每次都必定會去嘗試獲取信號量

Hystrix的配置參數

Hystrix 的大部分配置都是 hystrix.command.[HystrixCommandKey] 開頭

其中 [HystrixCommandKey] 是可變的,默認是 default,即:hystrix.command.default(對於 Zuul 而言,CommandKey 就是 service id)

它常見的有如下幾個配置

  • hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds
    用來設置 thread 和 semaphore 兩種隔離策略的超時時間,默認值是1000
    建議設置這個參數,在 Hystrix-1.4.0 以前,semaphore-isolated 隔離策略是不能超時的,1.4.0 開始 semaphore-isolated 也支持超時時間了

  • hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests
    此值並不是 TPS、QPS、RPS 等都是相對值,它指的是 1 秒時間窗口內的事務 / 查詢 / 請求,它是一個絕對值,無時間窗口
    至關於亞毫秒級的,指任意時間點容許的併發數,當請求達到或超過該設置值後,其其他就會被拒絕,默認值是100

  • hystrix.command.default.execution.timeout.enabled
    是否開啓超時,默認爲true

  • hystrix.command.default.execution.isolation.thread.interruptOnTimeout
    發生超時是是否中斷線程,默認是true

  • hystrix.command.default.execution.isolation.thread.interruptOnCancel
    取消時是否中斷線程,默認是false

  • hystrix.command.default.circuitBreaker.requestVolumeThreshold
    當在配置時間窗口內達到此數量的失敗後,進行短路,默認20個

  • hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds
    短路多久之後開始嘗試是否恢復,默認5s

  • hystrix.command.default.circuitBreaker.errorThresholdPercentage
    出錯百分比閾值,當達到此閾值後,開始短路,默認50%

  • hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests
    調用線程容許請求 HystrixCommand.GetFallback() 的最大數量,默認10,超出時將會有異常拋出
    注意:該項配置對於 thread 隔離模式也起做用

以上就是列舉的一些常見配置,更多內容可參考:https://github.com/Netflix/Hystrix/wiki/Configuration

示例代碼

示例代碼以下(也能夠直接從 Github 下載:https://github.com/v5java/demo-cloud-06-hystrix

它是由四個模塊組成的 Maven 工程,其中包含一個註冊中心、一個服務提供者、兩個服務消費者

這是公共的 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.jadyer.demo</groupId>
    <artifactId>demo-cloud-06-hystrix</artifactId>
    <version>1.1</version>
    <packaging>pom</packaging>
    <modules>
        <module>service-client-01</module>
        <module>service-client-02</module>
        <module>service-discovery</module>
        <module>service-server</module>
    </modules>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.5.RELEASE</version>
    </parent>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Camden.SR6</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

註冊中心

這是註冊中心的 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.jadyer.demo</groupId>
        <artifactId>demo-cloud-06-hystrix</artifactId>
        <version>1.1</version>
    </parent>
    <artifactId>service-discovery</artifactId>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
        </dependency>
    </dependencies>
</project>

這是註冊中心的配置文件 /src/main/resources/application.yml

server:
  port: 1100

eureka:
  server:
    enable-self-preservation: false       # 關閉自我保護模式(缺省爲打開)
    eviction-interval-timer-in-ms: 1000   # 續期時間,即掃描失效服務的間隔時間(缺省爲60*1000ms)
  client:
    # 設置是否從註冊中心獲取註冊信息(缺省true)
    # 由於這是一個單點的EurekaServer,不須要同步其它EurekaServer節點的數據,故設爲false
    fetch-registry: false
    # 設置是否將本身做爲客戶端註冊到註冊中心(缺省true)
    # 這裏爲不須要(查看@EnableEurekaServer註解的源碼,會發現它間接用到了@EnableDiscoveryClient)
    register-with-eureka: false
    # 在未設置defaultZone的狀況下,註冊中心在本例中的默認地址就是http://127.0.0.1:1100/eureka/
    # 但奇怪的是,啓動註冊中心時,控制檯仍是會打印這個地址的節點:http://localhost:8761/eureka/
    # 而實際服務端註冊時,要使用1100端口的才能註冊成功,8761端口的會註冊失敗並報告異常
    serviceUrl:
      # 實際測試:若修改尾部的eureka爲其它的,好比/myeureka,註冊中心啓動沒問題,但服務端在註冊時會失敗
      # 報告異常:com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server
      defaultZone: http://127.0.0.1:${server.port}/eureka/

這是註冊中心的 SpringBoot 啓動類 ServiceDiscoveryBootStrap.java

package com.jadyer.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

//建立服務註冊中心
@EnableEurekaServer
@SpringBootApplication
public class ServiceDiscoveryBootStrap {
    public static void main(String[] args) {
        SpringApplication.run(ServiceDiscoveryBootStrap.class, args);
    }
}

服務提供方

這是服務提供方的 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.jadyer.demo</groupId>
        <artifactId>demo-cloud-06-hystrix</artifactId>
        <version>1.1</version>
    </parent>
    <artifactId>service-server</artifactId>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
    </dependencies>
</project>

這是服務提供方的配置文件 /src/main/resources/application.yml

server:
  port: 2100

spring:
  application:
    name: CalculatorServer                        # 指定發佈的微服務名(之後調用時,只需該名稱便可訪問該服務)

eureka:
  instance:
    instance-id: ${spring.application.name}:${server.port}
    prefer-ip-address: true                       # 設置微服務調用地址爲IP優先(缺省爲false)
    lease-renewal-interval-in-seconds: 5          # 心跳時間,即服務續約間隔時間(缺省爲30s)
    lease-expiration-duration-in-seconds: 15      # 發呆時間,即服務續約到期時間(缺省爲90s)
  client:
    healthcheck:
      enabled: true                               # 開啓健康檢查(依賴spring-boot-starter-actuator)
    serviceUrl:
      defaultZone: http://127.0.0.1:1100/eureka/  # 指定服務註冊中心的地址

這是服務提供方的 SpringBoot 啓動類 ServiceServerBootStarp.java

package com.jadyer.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * 經過 @EnableEurekaClient 註解,爲服務提供方賦予註冊和發現服務的能力
 * ------------------------------------------------------------------------------------------------------------------
 * 也可使用org.springframework.cloud.client.discovery.@EnableDiscoveryClient註解
 * 詳見如下兩篇文章的介紹
 * http://cloud.spring.io/spring-cloud-static/Camden.SR3/#_registering_with_eureka
 * https://spring.io/blog/2015/01/20/microservice-registration-and-discovery-with-spring-cloud-and-netflix-s-eureka
 * ------------------------------------------------------------------------------------------------------------------
 * Created by 玄玉<https://jadyer.cn/> on 2017/1/9 16:00.
 */
@EnableEurekaClient
@SpringBootApplication
public class ServiceServerBootStarp {
    public static void main(String[] args) {
        SpringApplication.run(ServiceServerBootStarp.class, args);
    }
}

這是服務提供方暴露的數學運算服務 CalculatorController.java

package com.jadyer.demo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;

/**
 * 服務提供方暴露的數學運算服務
 * Created by 玄玉<https://jadyer.cn/> on 2017/1/9 16:00.
 */
@RestController
public class CalculatorController {
    private final Logger logger = LoggerFactory.getLogger(getClass());
    @Resource
    private DiscoveryClient client;

    @RequestMapping("/add")
    public int add(int a, int b){
        //加運算
        int result = a + b;
        //輸出服務信息
        ServiceInstance instance = client.getLocalServiceInstance();
        logger.info("uri={},serviceId={},result={}", instance.getUri(), instance.getServiceId(), result);
        //返回結果
        return result;
    }
}

服務消費方Ribbon的斷路

這是服務消費方Ribbon的 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.jadyer.demo</groupId>
        <artifactId>demo-cloud-06-hystrix</artifactId>
        <version>1.1</version>
    </parent>
    <artifactId>service-client-01</artifactId>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
        </dependency>
    </dependencies>
</project>

這是服務消費方Ribbon的配置文件 /src/main/resources/application.yml

server:
  port: 3100

spring:
  application:
    name: client-consumer-ribbon

eureka:
  instance:
    instance-id: ${spring.application.name}:${server.port}
    prefer-ip-address: true
    lease-renewal-interval-in-seconds: 5
    lease-expiration-duration-in-seconds: 15
  client:
    healthcheck:
      enabled: true
    serviceUrl:
      defaultZone: http://127.0.0.1:1100/eureka/

這是服務消費方Ribbon的 SpringBoot 啓動類 ServiceClient01BootStarp.java

package com.jadyer.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

//@SpringCloudApplication
//開啓斷路器功能
@EnableCircuitBreaker
@EnableEurekaClient
@SpringBootApplication
public class ServiceClient01BootStarp {
    //開啓軟均衡負載
    @LoadBalanced
    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(ServiceClient01BootStarp.class, args);
    }
}

這是服務消費方Ribbon的,包含了斷路器配置的,遠程服務調用實現 CalculatorService.java

package com.jadyer.demo.ribbon;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;

@Service
class CalculatorService {
    @Resource
    private RestTemplate restTemplate;

    //指定斷路後的回調方法(回調方法必須與原方法參數類型相同、返回值類型相同、方法名能夠不一樣)
    @HystrixCommand(fallbackMethod="addServiceToFallback")
    int addService(int a, int b){
        String reqURL = "http://CalculatorServer/add?a=" + a + "&b=" + b;
        return restTemplate.getForEntity(reqURL, Integer.class).getBody();
    }

    public int addServiceToFallback(int aa, int bb){
        return -999;
    }
}

這是服務消費方Ribbon的調用示例 ConsumerController.java

package com.jadyer.demo.ribbon;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;

/**
 * 服務調用方
 * Created by 玄玉<https://jadyer.cn/> on 2017/1/10 18:23.
 */
@RestController
@RequestMapping("/demo/ribbon")
public class ConsumerController {
    @Resource
    private CalculatorService calculatorService;

    @RequestMapping("/toadd")
    int toadd(int a, int b){
        return calculatorService.addService(a, b);
    }
}

服務消費方Feign的斷路

這是服務消費方Feign的 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.jadyer.demo</groupId>
        <artifactId>demo-cloud-06-hystrix</artifactId>
        <version>1.1</version>
    </parent>
    <artifactId>service-client-02</artifactId>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <!-- spring-cloud-starter-feign的內部已經包含了spring-cloud-starter-ribbon和spring-cloud-starter-hystrix -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>
    </dependencies>
</project>

這是服務消費方Feign的配置文件 /src/main/resources/application.yml

server:
  port: 3200

spring:
  application:
    name: client-consumer-feign

eureka:
  instance:
    instance-id: ${spring.application.name}:${server.port}
    prefer-ip-address: true
    lease-renewal-interval-in-seconds: 5
    lease-expiration-duration-in-seconds: 15
  client:
    healthcheck:
      enabled: true
    serviceUrl:
      defaultZone: http://127.0.0.1:1100/eureka/

這是服務消費方Feign的 SpringBoot 啓動類 ServiceClient02BootStarp.java

package com.jadyer.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;

//開啓Feign功能(無需顯式@EnableCircuitBreaker,其已含此功能)
@EnableFeignClients
@EnableEurekaClient
@SpringBootApplication
public class ServiceClient02BootStarp {
    public static void main(String[] args) {
        SpringApplication.run(ServiceClient02BootStarp.class, args);
    }
}

這是服務消費方Feign的,包含了斷路器配置的,遠程服務調用實現 CalculatorService.java

package com.jadyer.demo.feign;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

//綁定該接口到CalculatorServer服務,並通知Feign組件對該接口進行代理(不須要編寫接口實現)
@FeignClient(value="CalculatorServer", fallback=CalculatorService.HystrixCalculatorService.class)
public interface CalculatorService {
    ////@PathVariable這種也是支持的
    //@RequestMapping(value="/add/{a}", method=RequestMethod.GET)
    //int myadd(@PathVariable("a") int a, @RequestParam("b") int b);

    //經過SpringMVC的註解來配置所綁定的服務下的具體實現
    @RequestMapping(value="/add", method=RequestMethod.GET)
    int myadd(@RequestParam("a") int a, @RequestParam("b") int b);

    /**
     * 這裏採用和SpringCloud官方文檔相同的作法,把fallback類做爲內部類放入Feign接口中
     * http://cloud.spring.io/spring-cloud-static/Camden.SR6/#spring-cloud-feign-hystrix
     * (也能夠外面獨立定義該類,我的以爲不必,這種東西寫成內部類最合適)
     */
    @Component
    class HystrixCalculatorService implements CalculatorService {
        @Override
        public int myadd(@RequestParam("a") int a, @RequestParam("b") int b) {
            return -999;
        }
    }
}

這是服務消費方Feign的調用示例 ConsumerController.java

package com.jadyer.demo.feign;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;

/**
 * 服務調用方
 * Created by 玄玉<https://jadyer.cn/> on 2017/1/10 18:23.
 */
@RestController
@RequestMapping("/demo/feign")
public class ConsumerController {
    @Resource
    private CalculatorService calculatorService;

    @RequestMapping("/toadd")
    int toadd(int a, int b){
        return calculatorService.myadd(a, b);
    }
}

驗證

先不使用斷路器,而後啓動註冊中心、服務提供方、兩個服務消費方,而後分別訪問如下兩個接口

http://10.16.64.133:3100/demo/ribbon/toadd?a=11&b=22

http://10.16.64.133:3200/demo/feign/toadd?a=11&b=22

咱們會發現都正常的返回了計算結果:33

而後停掉服務提供方,再訪問兩個接口,咱們會看到下面的報警內容

# Ribbon會報告以下內容
Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Sat Apr 15 11:12:48 CST 2017
There was an unexpected error (type=Internal Server Error, status=500).
I/O error on GET request for "http://CalculatorServer/add": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect
# Feign會報告以下內容
Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Sat Apr 15 11:12:48 CST 2017
There was an unexpected error (type=Internal Server Error, status=500).
CalculatorService#myadd(int,int) timed-out and no fallback available.

而後咱們再啓用斷路器,並訪問兩個接口(此時服務提供方是關閉的),都會看到該應答:-999

相關文章
相關標籤/搜索