溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

SpringCloud-Hystrix實現(xiàn)原理是什么

發(fā)布時間:2021-05-31 14:20:06 來源:億速云 閱讀:204 作者:小新 欄目:開發(fā)技術(shù)

這篇文章給大家分享的是有關(guān)SpringCloud-Hystrix實現(xiàn)原理是什么的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

一、思維導(dǎo)圖

SpringCloud-Hystrix實現(xiàn)原理是什么

二、Hystrix包含的內(nèi)容

(1) 服務(wù)降級

1)什么是服務(wù)降級

有了服務(wù)的熔斷,隨之就會有服務(wù)的降級,所謂服務(wù)降級,就是當(dāng)某個服務(wù)熔斷之后,服務(wù)端提供的服務(wù)將不再被調(diào)用,此時由客戶端自己準(zhǔn)備一個本地的fallback回調(diào),返回一個默認(rèn)值來代表服務(wù)端的返回;

這種做法,雖然不能得到正確的返回結(jié)果,但至少保證了服務(wù)的可用,比直接拋出錯誤或者服務(wù)不可用要好很多。

2)如何進行服務(wù)降級

(1)服務(wù)端

1、POM

 <dependencies>
        <!--hystrix-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>com.tfjy.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

2、YML

server:
  port: 8001
 
spring:
  application:
    name: cloud-provider-hystrix-payment
 
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      #defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
      defaultZone: http://localhost:7001/eureka/

3、主啟動

需要在主啟動上加上

SpringCloud-Hystrix實現(xiàn)原理是什么

4、業(yè)務(wù)類

controller

 @GetMapping("/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id){
        String result = paymentService.paymentInfo_TimeOut(id);
        log.info("*****result"+result);
        return result;
    }

service

 @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",commandProperties = {
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="5000")
    })
    public String paymentInfo_TimeOut(Integer id){
       try{
           TimeUnit.SECONDS.sleep(5);
        }catch (InterruptedException e){
           e.printStackTrace();
        }
        return "線程池:"+Thread.currentThread().getName()+"paymentInfo_TimeOut,id"+id+"O(∩_∩)O哈哈~"+"耗時5秒鐘";
    }
 
    public String paymentInfo_TimeOutHandler(Integer id){
        return "線程池:"+Thread.currentThread().getName()+"paymentInfo_TimeOutHandler,id"+id+"o(╥﹏╥)o";
    }

在代碼上加上HystrixCommand注解,然后由個屬性fallbackMethod,value值可以填寫方法的名字。

當(dāng)發(fā)生超時的時候,就會走下面的方法。

SpringCloud-Hystrix實現(xiàn)原理是什么

1、POM

<dependencies>
    <!--openfeign-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <!--hystrix-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    <!--eureka client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!-- 引入自己定義的api通用包,可以使用Payment支付Entity -->
    <dependency>
        <groupId>com.tfjy.springcloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <!--web-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!--一般基礎(chǔ)通用配置-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

2、YML

server:
  port: 80
 
eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://localhost:7001/eureka/
 
feign:
  hystrix:
    enabled: true

3、主啟動

SpringCloud-Hystrix實現(xiàn)原理是什么

4、業(yè)務(wù)

@GetMapping("/consumer/payment/hystrix/timeout/{id}")
    @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",commandProperties = {
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")
    })
//    @HystrixCommand
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id)
    {
        int age = 10/0;
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        return result;
    }
    public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id)
    {
        return "我是消費者80,對方支付系統(tǒng)繁忙請10秒鐘后再試或者自己運行出錯請檢查自己,o(╥﹏╥)o";
    }
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class)
public interface PaymentHystrixService {
 
    @GetMapping("/payment/hystrix/ok/{id}")
    public   String paymentInfo_ok(@PathVariable("id") Integer id);
 
    @GetMapping("/payment/hystrix/timeout/{id}")
    public   String paymentInfo_TimeOut(@PathVariable("id") Integer id);
}

這個參數(shù)要一樣

這個只能等待1.5s但是在8001要5s

SpringCloud-Hystrix實現(xiàn)原理是什么

三、全局配置

@RestController
@Slf4j
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public class OrderHystirxController {
   @GetMapping("/consumer/payment/hystrix/timeout/{id}")
//    @HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",commandProperties = {
//            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")
//    })
    @HystrixCommand
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id)
    {
        int age = 10/0;
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        return result;
    }
    public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id)
    {
        return "我是消費者80,對方支付系統(tǒng)繁忙請10秒鐘后再試或者自己運行出錯請檢查自己,o(╥﹏╥)o";
    }
 
    // 下面是全局fallback方法
    public String payment_Global_FallbackMethod()
    {
        return "Global異常處理信息,請稍后再試,/(ㄒoㄒ)/~~";
    }
}

@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")

1:1 每個方法配置一個服務(wù)降級方法,技術(shù)上可以,實際上傻X

1:N 除了個別重要核心業(yè)務(wù)有專屬,其它普通的可以通過@DefaultProperties(defaultFallback = "") 統(tǒng)一跳轉(zhuǎn)到統(tǒng)一處理結(jié)果頁面

通用和獨享的各自分開,避免了代碼膨脹,合理減少了代碼量

SpringCloud-Hystrix實現(xiàn)原理是什么

三、哪些情況會發(fā)生服務(wù)降級

(1) 程序運行異常 (當(dāng)我們把service方法中改成int i =10/0)

(2) 超時

(3) 服務(wù)熔斷觸發(fā)服務(wù)降級

(4) 線程池/信號量也會導(dǎo)致服務(wù)降級

(2) 服務(wù)熔斷

一、概念

(1)什么是服務(wù)熔斷

熔斷這一概念來源于電子工程中的斷路器(Circuit Breaker)。在互聯(lián)網(wǎng)系統(tǒng)中,當(dāng)下游服務(wù)因訪問壓力過大而響應(yīng)變慢或失敗,上游服務(wù)為了保護系統(tǒng)整體的可用性,可以暫時切斷對下游服務(wù)的調(diào)用。

在固定時間窗口內(nèi),接口調(diào)用超時比率達(dá)到一個閾值,會開啟熔斷。進入熔斷狀態(tài)后,后續(xù)對該服務(wù)接口的調(diào)用不再經(jīng)過網(wǎng)絡(luò),直接執(zhí)行本地的默認(rèn)方法,達(dá)到服務(wù)降級的效果。

熔斷不可能是永久的。當(dāng)經(jīng)過了規(guī)定時間之后,服務(wù)將從熔斷狀態(tài)回復(fù)過來,再次接受調(diào)用方的遠(yuǎn)程調(diào)用。

(2)熔斷的三種狀態(tài)

SpringCloud-Hystrix實現(xiàn)原理是什么

  • 熔斷關(guān)閉狀態(tài)(Closed) 服務(wù)沒有故障時,熔斷器所處的狀態(tài),對調(diào)用方的調(diào)用不做任何限制。

  • 熔斷開啟狀態(tài)(Open) 在固定時間窗口內(nèi)(Hystrix默認(rèn)是10秒),接口調(diào)用出錯比率達(dá)到一個閾值(Hystrix默認(rèn)為50),會進入熔斷開啟狀態(tài),進入熔斷狀態(tài)后,后續(xù)對該服務(wù)接口的調(diào)用不再經(jīng)過網(wǎng)絡(luò),直接執(zhí)行本地的fallback方法。

  • 半熔斷狀態(tài)(half-open)哎進入熔斷開啟狀態(tài)一段時間之后(Hystrix默認(rèn)是5秒),熔斷器會進入半熔斷狀態(tài),所謂半熔斷就是嘗試恢復(fù)服務(wù)調(diào)用,允許有限的流量調(diào)用該服務(wù),并監(jiān)控調(diào)用成功率,如果成功率達(dá)到了預(yù)期,則說明服務(wù)已恢復(fù),進入熔斷關(guān)閉狀態(tài);如果成功率仍舊很低,則重新進入熔斷關(guān)閉狀態(tài)。

二、配置熔斷

(2)pom

<dependencies>
        <!--hystrix-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency><!-- 引入自己定義的api通用包,可以使用Payment支付Entity -->
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

(2)YML

server:
  port: 8001
 
spring:
  application:
    name: cloud-provider-hystrix-payment
 
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      #defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
      defaultZone: http://eureka7001.com:7001/eureka

(3)主啟動

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

(4)業(yè)務(wù)

 //====服務(wù)熔斷
    @GetMapping("/payment/circuit/{id}")
    public String paymentCircuitBreaker(@PathVariable("id") Integer id)
    {
        String result = paymentService.paymentCircuitBreaker(id);
        log.info("****result: "+result);
        return result;
    }
 //=====服務(wù)熔斷
    @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),// 是否開啟斷路器
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),// 請求次數(shù)
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), // 時間窗口期
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),// 失敗率達(dá)到多少后跳閘
    })
    public String paymentCircuitBreaker(@PathVariable("id") Integer id)
    {
        if(id < 0)
        {
            throw new RuntimeException("******id 不能負(fù)數(shù)");
        }
        String serialNumber = IdUtil.simpleUUID();
 
        return Thread.currentThread().getName()+"\t"+"調(diào)用成功,流水號: " + serialNumber;
    }
    public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id)
    {
        return "id 不能負(fù)數(shù),請稍后再試,/(ㄒoㄒ)/~~   id: " +id;
    }

涉及到斷路器的三個重要參數(shù):快照時間窗、請求總數(shù)閾值、錯誤百分比閾值

1:快照時間窗: 斷路器確定是否打開需要統(tǒng)計一些請求和錯誤數(shù)據(jù),而統(tǒng)計的時間范圍就是快照時間窗,默認(rèn)為最近的10秒。

2: 請求總數(shù)閾值: 在快照時間窗內(nèi),必須滿足請求總數(shù)閾值才有資格熔斷。默認(rèn)為20,意味著在10秒內(nèi),如果該hystrix命令的調(diào)用次數(shù)不足20次,即使所有的請求都超時或其他原因失敗,斷路器都不會打開。

3: 錯誤百分比閾值:當(dāng)請求總數(shù)在快照時間窗口內(nèi)超過了閾值,比如發(fā)生了30次調(diào)用,如果在這30次調(diào)用中,有15次發(fā)生了超時異常,也就是超過50%的錯誤百分比,在默認(rèn)設(shè)定50%閾值情況下,這時候就會將斷路器打開。

(3) 服務(wù)限流

1、限流概念

Hystrix把一個分布式系統(tǒng)的某一個服務(wù)打造成一個高可用的服務(wù)最重要的手段之一就是資源隔離,即通過限流來限制對某一服務(wù)的訪問量,比如說對Mysql的訪問,為了避免過大的流量直接請求mysql服務(wù),hstrix通過線程池或者信號量技術(shù)進行限流訪問。

我們了解到Hystrix的兩種隔離技術(shù):線程池和信號量。線程池和信號量,也分析了在什么樣的場景下使用線程池和信號量,通常來說線程池資源隔離技術(shù)一般用于對依賴服務(wù)的網(wǎng)絡(luò)請求訪問,需要解決timeout問題。信號量則適合對內(nèi)部的一些比較復(fù)雜的業(yè)務(wù)邏輯訪問,不涉及任何的網(wǎng)絡(luò)請求,當(dāng)并發(fā)量超過計數(shù)器指定值時,直接拒絕。

線程池隔離的最大優(yōu)點在于:任何一個依賴服務(wù)都可以被隔離在自己的線程池內(nèi),即使自己的線程池資源填滿了,也不會影響任何其他的服務(wù)調(diào)用。最大缺點在于:增加了cpu的開銷,除了tomcat本身的調(diào)用線程之外,還有hystrix自己管理的線程池。每個command的執(zhí)行都依托一個獨立的線程,會進行排隊,調(diào)度,還有上下文切換。

2、資源隔離

(1)線程隔離

Service

//------------------線程隔離
    //groupKey 一組command ,如果沒有配這個,相同的groupkey會使用同一個線程池
    @HystrixCommand(groupKey = "thread1-group",commandKey = "thread1",threadPoolKey = "thread1",commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "30000")
    },threadPoolProperties = {
            @HystrixProperty(name = "coreSize",value = "3"),
            @HystrixProperty(name = "maxQueueSize",value = "5")
    })
    public void thread1(){
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            System.out.println(111);
        }
        System.out.println(Thread.currentThread().getName());
    }

controller

 @GetMapping("getThread")
    public void getThread(){
        System.out.println(Thread.currentThread().getName());
        paymentService.thread1();
    }

當(dāng)請求getThread的時候

http-nio-8001-exec-1
hystrix-thread1-1
http-nio-8001-exec-3
hystrix-thread1-2

會發(fā)現(xiàn)兩個線程池是不一樣的。

我現(xiàn)在在service中再添加一個

 //------------------線程隔離
    //groupKey 一組command ,如果沒有配這個,相同的groupkey會使用同一個線程池
    @HystrixCommand(groupKey = "thread1-group",commandKey = "thread1",threadPoolKey = "thread1",commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
    },threadPoolProperties = {
            @HystrixProperty(name = "coreSize",value = "3"),
            @HystrixProperty(name = "maxQueueSize",value = "5")
    })
    public void thread1(){
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            System.out.println(111);
        }
        System.out.println(Thread.currentThread().getName());
    }
    @HystrixCommand(groupKey = "thread2-group",commandKey = "thread2",threadPoolKey = "thread2",threadPoolProperties = {
            @HystrixProperty(name = "coreSize",value = "3"),
            @HystrixProperty(name = "maxQueueSize",value = "5"),
    },commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1000")})
    public void thread2(){
        System.out.println(111);
        System.out.println(Thread.currentThread().getName());
    }

在controller中調(diào)用

 @GetMapping("getThread")
    public void getThread(){
        System.out.println(Thread.currentThread().getName());
        paymentService.thread1();
        paymentService.thread2();
    }
http-nio-8001-exec-1
hystrix-thread1-1
111
hystrix-thread2-1
@HystrixProperty(name = "coreSize",value = "3"), ## 這個表示核心線程數(shù)
@HystrixProperty(name = "maxQueueSize",value = "5"), ## 這個表示這個隊列中的線程數(shù)為5個
所以這里面有8個

ps:下面看下對SpringCloud Hystrix的使用個人總結(jié)

和一般的開箱即用工具類似,SpringCloud Hystrix只需要最多四步即可基本使用上

1. 引入依賴:   spring-cloud-starter-hystrix

2. 添加支持:   在啟動類上添加@EnableHystrix

3. 具體使用:   在有熔斷需求的服務(wù)接口實現(xiàn)上標(biāo)注@HystrixCommand,指定發(fā)生熔斷時的回調(diào)方法

4. 按需配置:   比如配置熔斷時間

需要注意的是在具體使用環(huán)節(jié):

1. 回調(diào)方法必須在聲明@HystrixCommand的方法所在的類中,即回調(diào)方法必須是服務(wù)接口的兄弟方法

2. 回調(diào)方法的參數(shù)列表必須和服務(wù)接口的參數(shù)列表完全一致,否則報找不到回調(diào)方法異常.

回調(diào)方法保持與原接口參數(shù)列表強一致,說明回調(diào)方法就是原接口的替補接口,備胎接口.

通過對Hystrix的使用總結(jié),再次驗證了開箱即用工具的使用套路.

1.引入依賴

2.添加支持

3.具體使用

4.按需配置

感謝各位的閱讀!關(guān)于“SpringCloud-Hystrix實現(xiàn)原理是什么”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI