1. 程式人生 > >Spring Cloud熔斷器Hystrix的使用及原理解析

Spring Cloud熔斷器Hystrix的使用及原理解析

什麼是Hystrix

Hystrix是Spring Cloud提供的一種帶有熔斷機制的框架,由於在微服務系統中同一個操作會由多個不同的微服務來共同完成,所以微服務與微服務之間會由很多相互的呼叫,由於在分散式環境中經常會出現某個微服務節點故障的情況,所以會由呼叫失敗發生,而熔斷器的作用就是當出現遠端呼叫失敗的時候提供一種機制來保證程式的正常執行而不會卡死在某一次呼叫,類似Java程式中的try-catch結構,而只有當異常發生的時候才會進入catch的程式碼塊。

使用Hystrix

建立提供服務的伺服器

首先構建一個提供服務的伺服器專案spring-cloud-server,在其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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <
groupId
>
tech.codemine</groupId> <artifactId>spring-cloud-server</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</
artifactId
>
<version>2.0.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>

接著在專案中新建一個名為hello的package,然後在其中建立一個名為ServerApplication.java的檔案,程式碼如下:

package hello;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@SpringBootApplication
public class ServerApplication {

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

    @RequestMapping("/hello")
    public String hello() {
        return "hello from server";
    }
}

然後在resources目錄下建立application.yml檔案,裡面設定服務的埠號,如下:

server:
  port: 8081

整個專案的結構如下:
在這裡插入圖片描述
然後啟動專案

建立客戶端

接著建立連線伺服器的客戶端,首先建立一個名為hystrix-in-action的專案,專案的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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>tech.codemine</groupId>
    <artifactId>hystrix-in-action</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

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

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

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

接著同樣建立一個名為hello的package,然後在其中建立一個名為HystrixApplication.java的檔案,程式碼如下:

package hello;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@EnableHystrix
@SpringBootApplication
public class HystrixApplication {

    @Autowired
    HystrixService hystrixService;

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

    @RequestMapping("/hi")
    public String hi() {
        return hystrixService.hi();
    }
}


然後建立一個名為HystrixService.java的檔案,程式碼如下:

package hello;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class HystrixService {

    @HystrixCommand(fallbackMethod = "fallback")
    public String hi() {
        return new RestTemplate().getForObject("http://localhost:8081/hello", String.class);
    }

    public String fallback() {
        return "fallback";
    }
}

整個工程的目錄如下:

在這裡插入圖片描述
然後啟動專案

測試

我們可以通過IDEA自帶的REST Client工具發起HTTP請求進行測試,當然也可以直接在瀏覽器中輸入地址進行測試。

首先輸入http://localhost:8081/hi,可以看到得到了“hello from server”的結果,接著關閉spring-cloud-server工程,再次發起請求,可以發現這次得到的結果是“fallback”。

結果解釋

在HystrixService類中,我們使用了文章一開始所描述的熔斷器機制,在hi()方法中加入了HystrixCommand註解,在註解中我們提供了一個名為“fallback”的欄位,這個方法指向的是同一個類中的fallback()方法,當hi()方法呼叫失敗的時候就會自動轉而執行fallback()方法。

Hystrix原始碼解析

Hystrix在底層使用了Spring提供的切面技術。

在HystrixCommandAspect.java檔案中可以看到定義的切面:

/**
 * AspectJ aspect to process methods which annotated with {@link HystrixCommand} annotation.
 */
@Aspect
public class HystrixCommandAspect {

    private static final Map<HystrixPointcutType, MetaHolderFactory> META_HOLDER_FACTORY_MAP;

    static {
        META_HOLDER_FACTORY_MAP = ImmutableMap.<HystrixPointcutType, MetaHolderFactory>builder()
                .put(HystrixPointcutType.COMMAND, new CommandMetaHolderFactory())
                .put(HystrixPointcutType.COLLAPSER, new CollapserMetaHolderFactory())
                .build();
    }

    @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)")

    public void hystrixCommandAnnotationPointcut() {
    }

    @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser)")
    public void hystrixCollapserAnnotationPointcut() {
    }

    @Around("hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()")
    public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable {
        //通過切點獲取被攔截的方法
        Method method = getMethodFromTarget(joinPoint);
        Validate.notNull(method, "failed to get method from joinPoint: %s", joinPoint);
        if (method.isAnnotationPresent(HystrixCommand.class) && method.isAnnotationPresent(HystrixCollapser.class)) {
            throw new IllegalStateException("method cannot be annotated with HystrixCommand and HystrixCollapser " +
                    "annotations at the same time");
        }
        MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method));
        //metaholder中儲存了很多和切點相關的資訊,詳見後文的貼圖
        MetaHolder metaHolder = metaHolderFactory.create(joinPoint);
        HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder);
        ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ?
                metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType();
        
        //result中保留操作的結果,可能是成功操作的返回值也可能是fallback方法的返回值
        Object result;
        try {
            //如果返回的結果使用了observable模式則執行以下程式碼
            if (!metaHolder.isObservable()) {
                result = CommandExecutor.execute(invokable, executionType, metaHolder);
            } else {
            //否則執行else
                result = executeObservable(invokable, executionType, metaHolder);
            }
        } catch (HystrixBadRequestException e) {
            throw e.getCause() != null ? e.getCause() : e;
        } catch (HystrixRuntimeException e) {
            throw hystrixRuntimeExceptionToThrowable(metaHolder, e);
        }
        return result;
    }
    ..........
}

可以看到在這個類中首先是定義了兩個切面,由於我們這裡討論的是HystrixCommand,所以只關注第一個切面,在這個切面裡可以看到切點是被HystrixCommand註解的方法,然後對方法的具體增強是在接下來的一個名為methodsAnnotatedWithHystrixCommand()的方法裡,具體的流程用註釋寫在了程式碼中。

metaHolder的內容:
在這裡插入圖片描述
可以看到在以上程式碼中,最重要的便是獲取到result具體結果的那一步,由於我們的例子不是使用,所以重點放在

result = CommandExecutor.execute(invokable, executionType, metaHolder);

接下來跳轉到CommandExecutor.java中的execute()方法

/**
     * Calls a method of {@link HystrixExecutable} in accordance with specified execution type.
     *
     * @param invokable  {@link HystrixInvokable}
     * @param metaHolder {@link MetaHolder}
     * @return the result of invocation of specific method.
     * @throws RuntimeException
     */
    public static Object execute(HystrixInvokable invokable, ExecutionType executionType, MetaHolder metaHolder) throws RuntimeException {
        Validate.notNull(invokable);
        Validate.notNull(metaHolder);

        switch (executionType) {
            case SYNCHRONOUS: {
                return castToExecutable(invokable, executionType).execute();
            }
            case ASYNCHRONOUS: {
                HystrixExecutable executable = castToExecutable(invokable, executionType);
                if (metaHolder.hasFallbackMethodCommand()
                        && ExecutionType.ASYNCHRONOUS == metaHolder.getFallbackExecutionType()) {
                    return new FutureDecorator(executable.queue());
                }
                return executable.queue();
            }
            case OBSERVABLE: {
                HystrixObservable observable = castToObservable(invokable);
                return ObservableExecutionMode.EAGER == metaHolder.getObservableExecutionMode() ? observable.observe() : observable.toObservable();
            }
            default:
                throw new RuntimeException("unsupported execution type: " + executionType);
        }
    }

在execute()方法中使用了rxjava的觀察者模式並最終在這裡計算出結果返回。當出現失敗是,會呼叫GenericCommand.java中的getFallBack()方法,程式碼如下:

/**
     * The fallback is performed whenever a command execution fails.
     * Also a fallback method will be invoked within separate command in the case if fallback method was annotated with
     * HystrixCommand annotation, otherwise current implementation throws RuntimeException and leaves the caller to deal with it
     * (see {@link super#getFallback()}).
     * The getFallback() is always processed synchronously.
     * Since getFallback() can throw only runtime exceptions thus any exceptions are thrown within getFallback() method
     * are wrapped in {@link FallbackInvocationException}.
     * A caller gets {@link com.netflix.hystrix.exception.HystrixRuntimeException}
     * and should call getCause to get original exception that was thrown in getFallback().
     *
     * @return result of invocation of fallback method or RuntimeException
     */
    @Override
    protected Object getFallback() {
        final CommandAction commandAction = getFallbackAction();
        if (commandAction != null) {
            try {
                return process(new Action() {
                    @Override
                    Object execute() {
                        MetaHolder metaHolder = commandAction.getMetaHolder();
                        Object[] args = createArgsForFallback(metaHolder, getExecutionException());
                        return commandAction.executeWithArgs(metaHolder.getFallbackExecutionType(), args);
                    }
                });
            } catch (Throwable e) {
                LOGGER.error(FallbackErrorMessageBuilder.create()
                        .append(commandAction, e).build());
                throw new FallbackInvocationException(unwrapCause(e));
            }
        } else {
            return super.getFallback
            
           

相關推薦

Spring Cloud熔斷器Hystrix的使用原理解析

什麼是Hystrix Hystrix是Spring Cloud提供的一種帶有熔斷機制的框架,由於在微服務系統中同一個操作會由多個不同的微服務來共同完成,所以微服務與微服務之間會由很多相互的呼叫,由於在分散式環境中經常會出現某個微服務節點故障的情況,所以會由呼叫失敗發生,而熔斷器的作用就是

第三章、spring cloud---feign+Hystrix熔斷器

熔斷器 雪崩效應 在微服務架構中通常會有多個服務層呼叫,基礎服務的故障可能會導致級聯故障,進而造成整個系統不可用的情況,這種現象被稱為服務雪崩效應。服務雪崩效應是一種因“服務提供者”的不可用導致“服務消費者”的不可用,並將不可用逐漸放大的過程。 如果下圖所示:A作為服務提供者,B

1、spring cloud---feign+Hystrix熔斷器實現(第三章)

Feign-Hystrix 因為熔斷只是作用在服務呼叫這一端,因此我們根據上一篇的示例程式碼只需要改動spring-cloud-consumer專案相關程式碼就可以。因為,Feign中已經依賴了Hystrix所以在maven配置上不用做任何改動。 1、配置檔案 application

Spring CloudHystrix、RibbonFeign的熔斷關係是什麼?

導讀   今天和大家聊一聊在Spring Cloud微服務框架實踐中,比較核心但是又很容易把人搞得稀裡糊塗的一個問題,那就是在Spring Cloud中Hystrix、Ribbon以及Feign它們三者之間在處理微服務呼叫超時從而觸發熔斷降級的關係是什麼?   我們知道在Spr

Spring源碼:IOC原理解析(二)

main 節點 定義 nat ner multicast esp loading more 版權聲明:本文為博主原創文章,轉載請註明出處,歡迎交流學習! 接著上一章節的內容,我們來分析當new一個FileSystemXmlApplicationContext對

筆記:Spring Cloud Feign Hystrix 配置

微軟 lba one 機制 service () 指定 disable end 在 Spring Cloud Feign 中,除了引入了用戶客戶端負載均衡的 Spring Cloud Ribbon 之外,還引入了服務保護與容錯的工具 Hystrix,默認情況下,Spring

MyBatis框架中Mapper映射配置的使用原理解析(二) 配置篇 SqlSessionFactoryBuilder,XMLConfigBuilder

.cn 創建 ron 子節點 homepage 解析 調用 sco title 在 <MyBatis框架中Mapper映射配置的使用及原理解析(一) 配置與使用> 的demo中看到了SessionFactory的創建過程: SqlSessionFactory

spring-cloud-starter-hystrix(斷路器)服務不通或者調用失敗後的錯誤處理和回調

系統 comm cli 處理 參考 quest 微服務架構 ron 100% 雪崩效應 在微服務架構中通常會有多個服務層調用,大量的微服務通過網絡進行通信,從而支撐起整個系統。各個微服務之間也難免存在大量的依賴關系。然而任何服務都不是100%可用的,網絡往往也是脆弱的,所

防雪崩利器:熔斷器 Hystrix原理與使用

http 加鎖 針對 網絡 fall source 更新 由於 行修改 原文地址:https://segmentfault.com/a/1190000005988895 前言 分布式系統中經常會出現某個基礎服務不可用造成整個系統不可用的情況, 這種現象被稱為服務雪崩效應.

防雪崩利器:熔斷器 Hystrix原理與使用(轉)

ring bug 導致 運行 ade 新的 not metrics exceptio https://segmentfault.com/a/1190000005988895 前言 分布式系統中經常會出現某個基礎服務不可用造成整個系統不可用的情況, 這種現象被稱為服務雪崩效應

spring cloud feign+hystrix

exe interface hystrix rup rest log println exec pen server: port: 8081 spring: application: name: spring-hy-sale feign: hystri

Spring Cloud斷路器Hystrix

static 服務架構 系統 介紹 cover log was doc 故障   在微服務架構中,存在著那麽多的服務單元,若一個單元出現故障,就會因依賴關系形成故障蔓延,最終導致整個系統的癱瘓,這樣的架構相較傳統架構就更加的不穩定。為了解決這樣的問題,因此產生了斷路器模式。

架構師系列文:通過Spring Cloud元件Hystrix合併請求 架構師入門:Spring Cloud系列,Hystrix與Eureka的整合

    在前文裡,我們講述了通過Hystrix進行容錯處理的方式,這裡我們將講述通過Hystrix合併請求的方式     哪怕一個URL請求呼叫的功能再簡單,Web應用服務都至少會開啟一個執行緒來提供服務,換句話說,有效降低URL請求數能很大程度上降低系統的負載。通過

Python3中goto 語句的使用原理解析

【時間】2018.11.03 【題目】Python3中goto 語句的使用及原理解析 概述 本文轉載自https://blog.csdn.net/yilovexing/article/details/81092388,在此基礎上增加了原理的一點說明。     熟悉

Spring中@Autowire的底層原理解析(附詳細原始碼閱讀步驟)

搭建原始碼閱讀環境 首先在IDEA中建立一個Maven工程,然後在pom.xml中加入依賴,因為以後可能會用到其他的功能,所以這裡直接使用的是springboot的依賴 <?xml version="1.0" encoding="UTF-8"?> <project

架構師系列文:通過Spring Cloud元件Hystrix合併請求

    在前文裡,我們講述了通過Hystrix進行容錯處理的方式,這裡我們將講述通過Hystrix合併請求的方式     哪怕一個URL請求呼叫的功能再簡單,Web應用服務都至少會開啟一個執行緒來提供服務,換句話說,有效降低URL請求數能很大程度上降低系統

Spring CloudHystrix監控

結合Hystrix Dashboard實現Hystrix指標資料的視覺化面板 一、監控資料 1.pom.xml中加入 <dependency> <groupId>org.springframework.cloud</g

Spring Boot 靜態資源訪問原理解析

一、前言   springboot配置靜態資源方式是多種多樣,接下來我會介紹其中幾種方式,並解析一下其中的原理。 二、使用properties屬性進行配置   應該說 spring.mvc.static-path-pattern 和 spring.resources.static-locations這兩

阿里 Andfix 介紹原理解析

開源專案官方介紹: AndFix judges the methods should be replaced by java custom annotation and replaces it by hooking it. AndFix has a native

十三:Spring CloudHystrix Dashboard

1. 簡介 Hystrix是Netflix解決自己業務不穩定性的一個限流容錯框架,可以幫助我們解決微服務架構體系中的限流、降級、熔斷等功能。提高系統穩定性,提供了完善的監控實現,並且Hystrix可