總結下微服務中降級、熔斷,以及springcloud中Hystrix的原理以及實現


一、Hystrix

1、服務雪崩(遇到的問題)

       多個微服務之間調用的時候,假設微服務A調用微服務B和微服務C,微服務B和微服務C有調用其他的微服務,這就是所謂的”扇出”,如扇出的鏈路上某個微服務的調用響應式過長或者不可用,對微服務A的調用就會占用越來越多的系統資源,進而引起系統雪崩,所謂的”雪崩效應”。

2、Hystrix

       Hystrix是一個用於分布式系統的延遲和容錯的開源庫。在分布式系統里,許多依賴不可避免的調用失敗,比如超時、異常等,Hystrix能夠保證在一個依賴出問題的情況下,不會導致整個服務失敗,避免級聯故障,以提高分布式系統的彈性。

        “斷路器”本身是一種開關裝置,當某個服務單元發生故障監控(類似熔斷保險絲),向調用方法返回一個符合預期的、可處理的備選響應(FallBack),而不是長時間的等待或者拋出調用方法無法處理的異常,這樣就保證了服務調用方的線程不會被長時間、不必要地占用,從而避免了故障在分布式系統中的蔓延。乃至雪崩。

  • 觸發服務降級的場景(什么時候會觸發降級?)

    • 程序運行異常

    • 超時

    • 服務熔斷觸發服務降級

    • 線程池、信號量打滿也會導致服務降級

  • 服務熔斷處理(降級如何處理?)

    • 相當於保險絲,直接拉閘,服務的降級-》進而熔斷-》恢復調用鏈路

  • 服務限流

    • 秒殺高並發等操作

    • 使用的是Tomcat的內置線程池,所以在高並發下,可能服務會出現線程不夠用的情況

    • 接近實時的監控

  • 涉及到斷路器的三個重要參數

    @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),// 是否開啟斷路器
    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"),// 請求次數
    @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"), // 時間窗口期
    @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),// 失敗率達到多少后跳閘
    • 快照時間窗:斷路器確定是否打開需要統計一些請求和錯誤數據,而統計的時間范圍就是快照時間窗,默認為最近的10秒;

    • 請求總數閾值:在快照時間窗內,必須滿足請求總數閾值才有資格熔斷。默認是20,意味着在10秒內,如果該hystrix命令的調用次數不足20次,即使所有的請求都超時或其他原因失敗,斷路器都不會打開;

    • 錯誤百分比閾值:當請求總數在快照時間窗內超過了閾值,比如發生了30次調用,如果在這30次調用中,有15次發生了超時異常,也就是超過了50%的錯誤百分比,在默認設定的50%閾值情況下,這時候就會將斷路器打開。

  • 二、服務熔斷

            熔斷機制是應對雪崩效應的一種微服務鏈路保護機制,

            當扇出鏈路的某個微服務不可用或者響應時間太長時,會進行服務的降級,進而熔斷該節點微服務的調用,快速返回”錯誤”的響應信息。當檢測到該節點微服務響應正常后恢復調用鏈路,在SpringCloud框架機制通過Hystrix實現,Hystrix會監控微服務見調用的狀況,當失敗的調用到一個閾值,缺省是5秒內20次調用失敗就會啟動熔斷機制,熔斷機制的注解是@HystrixCommand

    創建一個工程,命名為:DeptProvider8001_Hystrix_App

    1、增加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">
        <parent>
            <artifactId>microservicecloud</artifactId>
            <groupId>com.yufeng.springcloud</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>microservicecloud-provider-dept-hystrix-8001</artifactId>
    
        <dependencies>
            <!-- hystrix -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-hystrix</artifactId>
            </dependency>
            <!-- 將微服務provider側注冊進eureka -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
            <!-- 引入自己定義的api通用包,可以使用Dept部門Entity -->
            <dependency>
                <groupId>com.yufeng.springcloud</groupId>
                <artifactId>microservicecloud-api</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
    
            <!-- actuator監控信息完善 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
            </dependency>
        </dependencies>
    </project>
    復制代碼

    2、yml文件修改,修改服務名稱instance-id:為自己的微服務名稱即可

    復制代碼
    server:
      port: 8001
    
    mybatis:
      config-location: classpath:mybatis/mybatis.cfg.xml        # mybatis配置文件所在路徑
      type-aliases-package: com.yufeng.springcloud.entities    # 所有Entity別名類所在包
      mapper-locations:
      - classpath:mybatis/mapper/**/*.xml                       # mapper映射文件
    
    spring:
       application:
        name: microservicecloud-dept
       datasource:
        type: com.alibaba.druid.pool.DruidDataSource            # 當前數據源操作類型
        driver-class-name: org.gjt.mm.mysql.Driver              # mysql驅動包
        url: jdbc:mysql://192.168.172.20:3306/cloudDB01              # 數據庫名稱
        username: root
        password: root
        dbcp2:
          min-idle: 5                                           # 數據庫連接池的最小維持連接數
          initial-size: 5                                       # 初始化連接數
          max-total: 5                                          # 最大連接數
          max-wait-millis: 200                                  # 等待連接獲取的最大超時時間
    
    
    eureka:
      client:  # 客戶端注冊進eureka內
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
      instance:
        instance-id: provider-hystrix-dept-8001
        prefer-ip-address: true  # 訪問路徑可以顯示IP
    
    info:
      app.name: yufeng-microservicecloud
      company.name: www.yufeng.com
      build.artifactId: $project.artifactId$
      build.version: $project.version$
    復制代碼

     

    3、增加熔斷機制(@HystrixCommand

    復制代碼
    @RestController
    public class DeptController
    {
        @Autowired
        private DeptService service;
    
        @RequestMapping(value = "/dept/add", method = RequestMethod.POST)
        public boolean add(@RequestBody Dept dept)
        {
            return service.add(dept);
        }
    
        @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
    //一旦調用服務方法失敗拋出“錯誤信息后,胡自動范湖用@HystrixCommand標注好的fallbackMethod調用類中的指定方法” @HystrixCommand(fallbackMethod = "processHystrixGet") public Dept get(@PathVariable("id") Long id) { Dept dept = service.get(id); //模擬異常 if(null == dept) { throw new RuntimeException("該id的信息不存在! id=" + id); } return service.get(id); } public Dept processHystrixGet(@PathVariable("id") Long id) { return new Dept().setDname("id沒有對應的信息, null -- @HystrixCommand, id=" + id) .setDb_source("no this database in MySQL."); } }
    復制代碼

    4、主啟動類添加注解 @EnableCircuitBreaker

    添加此注解告訴主啟動類對Hystrix的支持

    復制代碼
    @SpringBootApplication
    @EnableEurekaClient     //本服務啟動后自動注冊到eureka中
    @EnableCircuitBreaker   //對hystrixR熔斷機制的支持
    public class DeptProvider8001_Hystrix_App
    {
        public static void main(String[] args)
        {
            SpringApplication.run(DeptProvider8001_Hystrix_App.class, args);
        }
    }
    復制代碼

    5、測試:

    (1)啟動 3個eureka服務:EurekaServer7001、EurekaServer7002、EurekaServer7003;

    (2)啟動 DeptProvider8001_Hystrix_App 服務;

    (3)最后啟動DeptConsumer80_App 服務。

    (4)測試地址:

    http://localhost/consumer/dept/get/2

    http://localhost/consumer/dept/get/112

     三、服務降級

    服務降級的處理是在客戶端完成的,與服務端沒有關系。

    整體資源快不夠用了,忍痛將某些服務先關掉,待度過難關,再回來開啟。

    所謂降級,就是一般是從整體符合考慮,就是當某個服務熔斷之后,服務器將不再被調用,此刻客戶端可以自己准備一個本地的fallback回調,返回一個缺省值,這樣做,雖然服務水平下降,但好歹可用,比直接掛掉要強。

    1、修改消費者服務接口的提供者項目(microservicecloud-api),讓service接口實現一個FallbackFactory接口類DeptClientServiceFallbackFactory(千萬記得增加 @Component  注解);

    注意:直接在接口定義的熔斷機制中進行服務熔斷,之前在controller上的@HystrixCommand(fallbackMethod=”methodName”)將棄用

     

    復制代碼
    import com.yufeng.springcloud.entities.Dept;
    import feign.hystrix.FallbackFactory;
    import org.springframework.stereotype.Component;
    import java.util.List;
    
    @Component
    public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService>
    {
        @Override
        public DeptClientService create(Throwable throwable)
        {
            return new DeptClientService() {
                @Override
                public boolean add(Dept dept)
                {
                    return false;
                }
    
                @Override
                public Dept get(Long id)
                {
                    Dept dept = new Dept();
                    dept.setDeptno(id);
                    dept.setDname("該ID:" + id + "沒有對應的信息,Consumer客戶端提供的信息,此服務Provider已關閉");
                    dept.setDb_source("no this database in mysql");
                    return dept;
                }
    
                @Override
                public List<Dept> list()
                {
                    return null;
                }
            };
        }
    }
    復制代碼

    2、修改提供服務的service熔斷處理的機制

    此處是在公共的service對某個service的方法訪問出現異常后進行統一的fallback處理,即在 DeptClientService接口在注解@FeignClient 中添加 fallbackFactory 屬性值,該屬性賦值為實現FallbcakFactory接口的異常處理類

    復制代碼
    import com.yufeng.springcloud.entities.Dept;
    import org.springframework.cloud.netflix.feign.FeignClient;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import java.util.List;
    
    @FeignClient(value = "microservicecloud-dept", fallbackFactory = DeptClientServiceFallbackFactory.class)
    public interface DeptClientService
    {
        @RequestMapping(value = "/dept/add", method = RequestMethod.POST)
        public boolean add(@RequestBody Dept dept);
    
        @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
        public Dept get(@PathVariable("id") Long id);
    
        @RequestMapping(value = "/dept/get/list", method = RequestMethod.GET)
        public List<Dept> list();
    }
    復制代碼

    3、在消費者工程(microservicecloud-consumer-dept-feign)的yml文件增加如下內容,開啟feign中的hystrix

    feign:
      hystrix:
        enabled: true

     

    4、將 microservicecloud-api 工程重新打包,執行: mvn clean install

    5、測試

    (1)啟動3個 eureka 服務;

    (2)啟動 microservicecloud-provider-dept-8001 服務;

    (3)啟動 microservicecloud-consumer-dept-feign 服務;

    (4)在瀏覽器中訪問:http://localhost/consumer/dept/get/1

    (5)將 microservicecloud-provider-dept-8001 服務關閉,瀏覽器訪問:http://localhost/consumer/dept/get/1

四:springCloud服務降級的三種方式

1. 使用Hystrix配置降級,降級方法寫在Controller中,每個方法寫一個

pom導入依賴:
在這里插入圖片描述
feign調用服務啟用服務降級
在這里插入圖片描述
在主啟動類啟用hystrix
在這里插入圖片描述
在調用放配置降級方法
在這里插入圖片描述

2.降級方法寫在Controller中,寫一個統一的降級方法

controller上加上注解,設置統一默認的降級方法
在這里插入圖片描述
在每個方法上,加上注解@HystrixCommand
在這里插入圖片描述

 

3.定義feign接口的實現類,實現類的方法處理降級寫一個類,

繼承feign接口在feign借口中,加上注解

在這里插入圖片描述


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM