天天看點

Hystrix實作服務隔離、熔斷、降級防止服務雪崩案例

一、建立SpringBoot測試項目,pom依賴如下

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.zhq</groupId>
    <artifactId>hystrix</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>hystrix</name>
    <description>Hystrix實作服務隔離、熔斷、降級案例</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
        <dependency>
            <groupId>com.netflix.hystrix</groupId>
            <artifactId>hystrix-metrics-event-stream</artifactId>
            <version>1.5.12</version>
        </dependency>
        <dependency>
            <groupId>com.netflix.hystrix</groupId>
            <artifactId>hystrix-javanica</artifactId>
            <version>1.5.12</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
           

二、案例核心代碼

Hystrix實作服務隔離、熔斷、降級防止服務雪崩案例

1)、建立TestController類編寫兩個沒有配置Hystrix的接口,一個配置了Hystrix的接口

@RestController
public class TestController {

    @Autowired
    private TestService testService;


    /**
     * 沒有配置Hystrix的API01
     * @return
     */
    @RequestMapping("/noHystrixApi01")
    public Object noHystrixApi01(){
        JSONObject baidu =testService.getBaidu();
        System.out.println("目前線程名稱:" + Thread.currentThread().getName() + ",訂單服務調用會員服務:member:" + baidu);
        return baidu;
    }

    /**
     * 沒有配置Hystrix的API02
     * @return
     */
    @RequestMapping("/noHystrixApi02")
    public Object noHystrixApi02(){
        JSONObject baidu =testService.getBaidu();
        System.out.println("目前線程名稱:" + Thread.currentThread().getName() + ",訂單服務調用會員服務:member:" + baidu);
        return baidu;
    }

    /**
     * 有配置Hystrix的API
     * @return
     */
    @RequestMapping("/hystrixApi")
    public Object hystrixApi(){
        return new HaveHystrixTestApiService(testService).execute();
    }


}
           

2)、其中TestService代碼

@Service
public class TestService {

    public JSONObject getBaidu() {
        return HttpClientUtils.httpGet("http://www.baidu.com");
    }
}
           

3)、配置 Hystrix的核心代碼HaveHystrixTestApiService

原理:

1、 使用線程池隔離可以完全隔離第三方應用,請求線程可以快速放回。 2、 請求線程可以繼續接受新的請求,如果出現問題線程池隔離是獨立的不會影響其他應用。 

3、 當失敗的應用再次變得可用時,線程池将清理并可立即恢複,而不需要一個長時間的恢複。 

4、 獨立的線程池提高了并發性

缺點: 

線程池隔離的主要缺點是它們增加計算開銷(CPU)。每個指令的執行涉及到排隊、排程和上 下文切換都是在一個單獨的線程上運作的。

public class HaveHystrixTestApiService extends HystrixCommand<JSONObject> {
    @Autowired
    private TestService testService;

    public HaveHystrixTestApiService(TestService testService) {
        super(setter());
        this.testService = testService;
    }

    private static Setter setter() {

        // 服務分組
        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey("testGroup");
        // 服務辨別
        HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey("test");
        // 線程池名稱
        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey("test-pool");
        // #####################################################
        // 線程池配置 線程池大小為10,線程存活時間15秒 隊列等待的門檻值為100,超過100執行拒絕政策
        HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter().withCoreSize(10)
                .withKeepAliveTimeMinutes(15).withQueueSizeRejectionThreshold(100);
        // ########################################################
        // 指令屬性配置Hystrix 開啟逾時
        HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter()
                // 采用線程池方式實作服務隔離
                .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)
                // 禁止
                .withExecutionTimeoutEnabled(false);
        return HystrixCommand.Setter.withGroupKey(groupKey).andCommandKey(commandKey).andThreadPoolKey(threadPoolKey)
                .andThreadPoolPropertiesDefaults(threadPoolProperties).andCommandPropertiesDefaults(commandProperties);

    }

    @Override
    protected JSONObject run() throws Exception {
        JSONObject baidu = testService.getBaidu();
        System.out.println("目前線程名稱:" + Thread.currentThread().getName() + ",訂單服務調用會員服務:member:" + baidu);
        return baidu;
    }

    @Override
    protected JSONObject getFallback() {
        // 如果Hystrix發生熔斷,目前服務不可用,直接執行Fallback方法
        System.out.println("系統錯誤!");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", 500);
        jsonObject.put("msg", "系統錯誤!");
        return jsonObject;
    }
}
           

三、通過JMeter測試案例

1)、沒做接口保護的時候場景:

當并發請求noHystrixApi01接口線程池資源滿,導緻noHystrixApi02無法通路

Hystrix實作服務隔離、熔斷、降級防止服務雪崩案例
Hystrix實作服務隔離、熔斷、降級防止服務雪崩案例

啟動以後:

Hystrix實作服務隔離、熔斷、降級防止服務雪崩案例

沒做接口保護時:雖然我們是并發請求api01但是導緻api02也無法通路

其中api01:

Hystrix實作服務隔離、熔斷、降級防止服務雪崩案例

 api02:

Hystrix實作服務隔離、熔斷、降級防止服務雪崩案例

即他們共用一個線程池

2)壓測1)時如果通路有配置接口保護的hystrixApi接口 

Hystrix實作服務隔離、熔斷、降級防止服務雪崩案例

因為走的獨立線程池不受影響