天天看點

Circuit Breaker(熔斷)實作之spring-retry、hystrix

spring-retry

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>
           
// springboot啟動類
@EnableRetry
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

// 實作類正常方法
// openTimeout時間範圍内失敗maxAttempts次數後,熔斷打開resetTimeout時長
@CircuitBreaker(maxAttempts = 3, openTimeout = 3000L, resetTimeout = 5000L )
public String normalMethod(String param) {
    log.info("======== normalMethod ======== " + param);
    if (true) {
        throw new RuntimeException("方法異常");
    }
    return param;
}

// 降級方法
@Recover
public String recoverMethod(Throwable t, String param) {
    log.info("======== recoverMethod ======== " + param);
    return param;
}
           

日志如下, 觀察日志發現并沒有half-open半開過程,熔斷關閉後會每次重試maxAttempts次請求。還有一點,spring-retry不支援線程池、信号量隔離。

2019-12-20 18:43:30.552: ======== normalMethod ======== testParam

2019-12-20 18:43:30.553: ======== recoverMethod ======== testParam

2019-12-20 18:43:30.813: ======== normalMethod ======== testParam

2019-12-20 18:43:30.813: ======== recoverMethod ======== testParam

2019-12-20 18:43:31.456: ======== normalMethod ======== testParam

2019-12-20 18:43:31.456: ======== recoverMethod ======== testParam

2019-12-20 18:43:31.785: ======== recoverMethod ======== testParam

2019-12-20 18:43:33.589: ======== recoverMethod ======== testParam

2019-12-20 18:43:45.059: ======== normalMethod ======== testParam

2019-12-20 18:43:45.059: ======== recoverMethod ======== testParam

2019-12-20 18:43:45.579: ======== normalMethod ======== testParam

2019-12-20 18:43:45.579: ======== recoverMethod ======== testParam

2019-12-20 18:43:47.294: ======== normalMethod ======== testParam

2019-12-20 18:43:47.294: ======== recoverMethod ======== testParam

2019-12-20 18:43:47.757: ======== recoverMethod ======== testParam

2019-12-20 18:43:50.242: ======== recoverMethod ======== testParam

 hystrix

<dependency>
    <groupId>com.netflix.hystrix</groupId>
    <artifactId>hystrix-core</artifactId>
    <version>1.5.18</version>
</dependency>
<dependency>
    <groupId>com.netflix.hystrix</groupId>
    <artifactId>hystrix-javanica</artifactId>
    <version>1.5.18</version>
</dependency>
           
// springboot啟動類省略
// 由于沒有使用自動裝配,需要自己定義相關Bean
@Configuration
public class HystrixConfig {

    @Bean
    public HystrixCommandAspect hystrixCommandAspect() {
        return new HystrixCommandAspect();
    }

    @Bean
    public HystrixShutdownHook hystrixShutdownHook() {
        return new HystrixShutdownHook();
    }

    private class HystrixShutdownHook implements DisposableBean {

        @Override
        public void destroy() throws Exception {
            // Just call Hystrix to reset thread pool etc.
            Hystrix.reset();
        }

    }
}

// 預設熔斷規則是10秒鐘内,20次請求,存在50%失敗就熔斷5秒鐘時間
@HystrixCommand(fallbackMethod = "fallbackMethod",
		commandProperties = {@HystrixProperty(name = "execution.isolation.strategy", value = "SEMAPHORE"),
				@HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests", value = "200"),
				@HystrixProperty(name = "fallback.isolation.semaphore.maxConcurrentRequests", value = "200")})
public String normalMethod(String param) {
    log.info("======== normalMethod ======== " + param);
    if (true) {
        throw new RuntimeException("方法異常");
    }
    return param;
}

public String fallbackMethod(String param) {
    log.info("======== fallbackMethod ======== " + param);
    return param;
}
           

 日志如下, 觀察日志發現在熔斷開啟5秒過後存在half-open半開過程,會有一次正常請求發送。

2019-12-20 18:45:01.079: ======== normalMethod ======== testParam

2019-12-20 18:45:01.085: ======== fallbackMethod ======== testParam

2019-12-20 18:45:01.322: ======== normalMethod ======== testParam

2019-12-20 18:45:01.323: ======== fallbackMethod ======== testParam

2019-12-20 18:45:01.954: ======== normalMethod ======== testParam

2019-12-20 18:45:01.954: ======== fallbackMethod ======== testParam

2019-12-20 18:45:02.532: ======== normalMethod ======== testParam

2019-12-20 18:45:02.533: ======== fallbackMethod ======== testParam

2019-12-20 18:45:03.063: ======== normalMethod ======== testParam

2019-12-20 18:45:03.063: ======== fallbackMethod ======== testParam

2019-12-20 18:45:03.505: ======== normalMethod ======== testParam

2019-12-20 18:45:03.506: ======== fallbackMethod ======== testParam

2019-12-20 18:45:03.972: ======== normalMethod ======== testParam

2019-12-20 18:45:03.972: ======== fallbackMethod ======== testParam

2019-12-20 18:45:04.414: ======== normalMethod ======== testParam

2019-12-20 18:45:04.414: ======== fallbackMethod ======== testParam

2019-12-20 18:45:04.865: ======== normalMethod ======== testParam

2019-12-20 18:45:04.866: ======== fallbackMethod ======== testParam

2019-12-20 18:45:05.625: ======== normalMethod ======== testParam

2019-12-20 18:45:05.625: ======== fallbackMethod ======== testParam

2019-12-20 18:45:06.253: ======== normalMethod ======== testParam

2019-12-20 18:45:06.253: ======== fallbackMethod ======== testParam

2019-12-20 18:45:06.806: ======== normalMethod ======== testParam

2019-12-20 18:45:06.806: ======== fallbackMethod ======== testParam

2019-12-20 18:45:07.377: ======== normalMethod ======== testParam

2019-12-20 18:45:07.378: ======== fallbackMethod ======== testParam

2019-12-20 18:45:07.938: ======== normalMethod ======== testParam

2019-12-20 18:45:07.938: ======== fallbackMethod ======== testParam

2019-12-20 18:45:08.335: ======== normalMethod ======== testParam

2019-12-20 18:45:08.336: ======== fallbackMethod ======== testParam

2019-12-20 18:45:08.843: ======== normalMethod ======== testParam

2019-12-20 18:45:08.843: ======== fallbackMethod ======== testParam

2019-12-20 18:45:09.404: ======== normalMethod ======== testParam

2019-12-20 18:45:09.404: ======== fallbackMethod ======== testParam

2019-12-20 18:45:09.940: ======== normalMethod ======== testParam

2019-12-20 18:45:09.940: ======== fallbackMethod ======== testParam

2019-12-20 18:45:10.466: ======== normalMethod ======== testParam

2019-12-20 18:45:10.466: ======== fallbackMethod ======== testParam

2019-12-20 18:45:10.889: ======== normalMethod ======== testParam

2019-12-20 18:45:10.889: ======== fallbackMethod ======== testParam

2019-12-20 18:45:11.438: ======== fallbackMethod ======== testParam

2019-12-20 18:45:11.946: ======== fallbackMethod ======== testParam

2019-12-20 18:45:12.414: ======== fallbackMethod ======== testParam

2019-12-20 18:45:12.971: ======== fallbackMethod ======== testParam

2019-12-20 18:45:16.774: ======== normalMethod ======== testParam

2019-12-20 18:45:16.774: ======== fallbackMethod ======== testParam

2019-12-20 18:45:17.245: ======== fallbackMethod ======== testParam

2019-12-20 18:45:17.718: ======== fallbackMethod ======== testParam

2019-12-20 18:45:18.189: ======== fallbackMethod ======== testParam

2019-12-20 18:45:18.622: ======== fallbackMethod ======== testParam

2019-12-20 18:45:33.752: ======== normalMethod ======== testParam

2019-12-20 18:45:33.752: ======== fallbackMethod ======== testParam

2019-12-20 18:45:34.669: ======== fallbackMethod ======== testParam

2019-12-20 18:45:35.354: ======== fallbackMethod ======== testParam

2019-12-20 18:45:35.968: ======== fallbackMethod ======== testParam

2019-12-20 18:45:36.592: ======== fallbackMethod ======== testParam