1. 程式人生 > 其它 >SpringCloud07---Hystrix:服務熔斷

SpringCloud07---Hystrix:服務熔斷

1. 服務雪崩

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

2. 什麼是Hystrix

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

  2. “斷路器”

    本身是一種開關裝置,當某個服務單元發生故障之後,通過斷路器的故障監控 (類似熔斷保險絲) ,向呼叫方返回一個服務預期的,可處理的備選響應 (FallBack) ,而不是長時間的等待或者丟擲呼叫方法無法處理的異常,這樣就可以保證了服務呼叫方的執行緒不會被長時間,不必要的佔用,從而避免了故障在分散式系統中的蔓延,乃至雪崩。

Hystrix能幹嘛

  • 服務降級

  • 服務熔斷

  • 服務限流

  • 接近實時的監控

當一切正常時,請求流可以如下所示

3. 服務熔斷

  • 熔斷機制是賭贏雪崩效應的一種微服務鏈路保護機制

  • Hystrix會監控微服務間呼叫的狀況,當失敗的呼叫到一定閥值預設是5秒內20次呼叫失敗,就會啟動熔斷機制。

  • 熔斷機制的註解是:@HystrixCommand

測試案例

1、新建springcloud-provider-dept-hystrix-8001模組並拷貝springcloud-provider-dept–8001內的pom.xml、resource和Java程式碼進行初始化並調整。

【匯入hystrix依賴】

<!--匯入Hystrix依賴-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>

2、調整yml配置檔案

server:
  port: 8001
mybatis:
  type-aliases-package: com.qi.springcloud.pojo
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml

spring:
  application:
    name: springcloud-provider-dept-hystrix-8001
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8
    username: root
    password: 123456

# Eureka配置:配置服務註冊中心地址
eureka:
  client:
    service-url:
      # 註冊中心地址7001-7003
      defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/
  instance:
    instance-id: springcloud-provider-dept-hystrix-8001 #修改Eureka上的預設描述資訊
    prefer-ip-address: true

# info配置
info:
  app.name: springcloud-provider-dept-hystrix-8001
  company.name: 江蘇大學計算機學院

3、修改controller-->@HystrixCommand(fallbackMethod = "hystrixGet")

//提供Restful服務
@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    @HystrixCommand(fallbackMethod = "hystrixGet")
    @RequestMapping("/dept/get/{id}")//根據id查詢
    public Dept get(@PathVariable("id") Long id){
        Dept dept = deptService.queryById(id);
        if (dept==null){
            throw new RuntimeException("這個id=>"+id+",不存在該使用者,或資訊無法找到~");
        }
        return dept;
    }


    //根據id查詢備選方案(熔斷)
    public Dept hystrixGet(@PathVariable("id") Long id){
        return new Dept().setDeptno(id)
                .setDname("這個id=>"+id+",沒有對應的資訊,null---@Hystrix~")
                .setDb_source("在MySQL中沒有這個資料庫");
    }
}

4、為主啟動類新增對熔斷的支援註解@EnableCircuitBreaker

@SpringBootApplication
@EnableEurekaClient // EnableEurekaClient 客戶端的啟動類,在服務啟動後自動向註冊中心註冊服務
@EnableDiscoveryClient // 服務發現~
@EnableCircuitBreaker // 新增對熔斷的支援註解
public class DeptProvider_Hystrix_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProvider_Hystrix_8001.class,args);
    }
}

5、使用熔斷後,當訪問一個不存在的id時,前臺頁展示資料如下

4. 服務降級

4.1 什麼是服務降級

服務降級是指 當伺服器壓力劇增的情況下,根據實際業務情況及流量,對一些服務和頁面有策略的不處理,或換種簡單的方式處理,從而釋放伺服器資源以保證核心業務正常運作或高效運作。說白了,就是儘可能的把系統資源讓給優先順序高的服務。

資源有限,而請求是無限的。如果在併發高峰期,不做服務降級處理,一方面肯定會影響整體服務的效能,嚴重的話可能會導致宕機某些重要的服務不可用。所以,一般在高峰期,為了保證核心功能服務的可用性,都要對某些服務降級處理。比如當雙11活動時,把交易無關的服務統統降級,如檢視螞蟻深林,檢視歷史訂單等等。

服務降級主要用於什麼場景呢?當整個微服務架構整體的負載超出了預設的上限閾值或即將到來的流量預計將會超過預設的閾值時,為了保證重要或基本的服務能正常執行,可以將一些 不重要 或 不緊急 的服務或任務進行服務的 延遲使用 或 暫停使用。

4.2 服務降級需要考慮的問題

  • 那些服務是核心服務,哪些服務是非核心服務

  • 那些服務可以支援降級,那些服務不能支援降級,降級策略是什麼

  • 除服務降級之外是否存在更復雜的業務放通場景,策略是什麼?

自動降級分類

(1)超時降級:主要配置好超時時間和超時重試次數和機制,並使用非同步機制探測回覆情況

(2)失敗次數降級:主要是一些不穩定的api,當失敗呼叫次數達到一定閥值自動降級,同樣要使用非同步機制探測回覆情況

(3)故障降級:比如要呼叫的遠端服務掛掉了(網路故障、DNS故障、http服務返回錯誤的狀態碼、rpc服務丟擲異常),則可以直接降級。降級後的處理方案有:預設值(比如庫存服務掛了,返回預設現貨)、兜底資料(比如廣告掛了,返回提前準備好的一些靜態頁面)、快取(之前暫存的一些快取資料)

(4)限流降級:秒殺或者搶購一些限購商品時,此時可能會因為訪問量太大而導致系統崩潰,此時會使用限流來進行限制訪問量,當達到限流閥值,後續請求會被降級;降級後的處理方案可以是:排隊頁面(將使用者導流到排隊頁面等一會重試)、無貨(直接告知使用者沒貨了)、錯誤頁(如活動太火爆了,稍後重試)。

4.3 測試案例

1、在springcloud-api模組下的service包中新建降級配置類DeptClientServiceFallBackFactory.java

@Component
public class DeptClientServiceFallBackFactory implements FallbackFactory {

    @Override
    public DeptClientService create(Throwable cause) {
        return new DeptClientService() {
            @Override
            public Dept queryById(Long id) {
                return new Dept()
                        .setDeptno(id)
                        .setDname("id=>" + id + "沒有對應的資訊,客戶端提供了降級的資訊,這個服務現在已經被關閉")
                        .setDb_source("沒有資料~");
            }
            @Override
            public List<Dept> queryAll() {
                return null;
            }

            @Override
            public Boolean addDept(Dept dept) {
                return false;
            }
        };
    }
}

2、在DeptClientService中指定降級配置類DeptClientServiceFallBackFactory

@Component //註冊到spring容器中
//@FeignClient:微服務客戶端註解,value:指定微服務的名字,這樣就可以使Feign客戶端直接找到對應的微服務
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientServiceFallBackFactory.class)//fallbackFactory指定降級配置類
public interface DeptClientService {

    @GetMapping("/dept/get/{id}")
    public Dept queryById(@PathVariable("id") Long id);

    @GetMapping("/dept/list")
    public List<Dept> queryAll();

    @GetMapping("/dept/add")
    public Boolean addDept(Dept dept);
}

3、在springcloud-consumer-dept-feign模組中開啟降級

server:
  port: 80

# Eureka配置
eureka:
  client:
    register-with-eureka: false # 不向 Eureka註冊自己
    service-url: # 從三個註冊中心中隨機取一個去訪問
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

# 開啟降級feign.hystrix
feign:
  hystrix:
    enabled: true

4.4 服務熔斷和降級的區別

  • 服務熔斷—>服務端:某個服務超時或異常,引起熔斷~,類似於保險絲(自我熔斷)

  • 服務降級—>客戶端:從整體網站請求負載考慮,當某個服務熔斷或者關閉之後,服務將不再被呼叫,此時在客戶端,我們可以準備一個 FallBackFactory ,返回一個預設的值(預設值)。會導致整體的服務下降,但是好歹能用,比直接掛掉強。

  • 觸發原因不太一樣,服務熔斷一般是某個服務(下游服務)故障引起,而服務降級一般是從整體負荷考慮;管理目標的層次不太一樣,熔斷其實是一個框架級的處理,每個微服務都需要(無層級之分),而降級一般需要對業務有層級之分(比如降級一般是從最外圍服務開始)

  • 實現方式不太一樣,服務降級具有程式碼侵入性(由控制器完成/或自動降級),熔斷一般稱為自我熔斷。

熔斷,降級,限流

  • 限流:限制併發的請求訪問量,超過閾值則拒絕;

  • 降級:服務分優先順序,犧牲非核心服務(不可用),保證核心服務穩定;從整體負荷考慮;

  • 熔斷:依賴的下游服務故障觸發熔斷,避免引發本系統崩潰;系統自動執行和恢復

5. Dashboard 流監控

  1. 新建springcloud-consumer-hystrix-dashboard模組,新增依賴
<!--Hystrix依賴-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>
<!--dashboard依賴-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>
<!--Ribbon-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>
<!--Eureka-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>
<!--實體類+web-->
<dependency>
    <groupId>com.haust</groupId>
    <artifactId>springcloud-api</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--熱部署-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
</dependency>
  1. 主啟動類
@SpringBootApplication
// 開啟Dashboard
@EnableHystrixDashboard
public class DeptConsumerDashboard_9001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumerDashboard_9001.class,args);
    }
}
  1. 給springcloud-provider-dept-hystrix-8001模組下的主啟動類新增如下程式碼,新增監控
@SpringBootApplication
@EnableEurekaClient //EnableEurekaClient 客戶端的啟動類,在服務啟動後自動向註冊中心註冊服務
public class DeptProvider_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProvider_8001.class,args);
    }

    //增加一個 Servlet
    @Bean
    public ServletRegistrationBean hystrixMetricsStreamServlet(){
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
        //訪問該頁面就是監控頁面
        registrationBean.addUrlMappings("/actuator/hystrix.stream");
       
        return registrationBean;
    }
}
  1. 訪問:http://localhost:9001/hystrix