7、Spring Cloud Hystrix

1.Spring Cloud Hystrix簡介

(1).分佈式問題

  複雜分佈式體系結構中的應用程序有數十個依賴關係,每個依賴關係在某些時候將不可避免地失敗。

 

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

  對於高流量的應用來說,單一的後端依賴可能會導致所有服務器上的所有資源都在幾秒鐘內飽和。比失敗更糟糕的是,這些應用程序還可能導致服務之間的延遲增加,備份隊列,線程和其他系統資源緊張,導致整個系統發生更多的級聯故障。這些都表示需要對故障和延遲進行隔離和管理,以便單個依賴關係的失敗,不能取消整個應用程序或系統。

  備註:一般情況對於服務依賴的保護主要有3中解決方案:

①.熔斷模式:這種模式主要是參考電路熔斷,如果一條線路電壓過高,保險絲會熔斷,防止火災。放到我們的系統中,如果某個目標服務調用慢或者有大量超時,此時,熔斷該服務的調用,對於後續調用請求,不在繼續調用目標服務,直接返回,快速釋放資源。如果目標服務情況好轉則恢復調用。

②.隔離模式:這種模式就像對系統請求按類型劃分成一個個小島的一樣,當某個小島被火少光了,不會影響到其他的小島。例如可以對不同類型的請求使用線程池來資源隔離,每種類型的請求互不影響,如果一種類型的請求線程資源耗盡,則對後續的該類型請求直接返回,不再調用後續資源。這種模式使用場景非常多,例如將一個服務拆開,對於重要的服務使用單獨服務器來部署,再或者公司最近推廣的多中心。

③.限流模式:上述的熔斷模式和隔離模式都屬於出錯後的容錯處理機制,而限流模式則可以稱爲預防模式。限流模式主要是提前對各個類型的請求設置最高的QPS閾值,若高於設置的閾值則對該請求直接返回,不再調用後續資源。這種模式不能解決服務依賴的問題,只能解決系統整體資源分配問題,因爲沒有被限流的請求依然有可能造成雪崩效應。

(2).Hystrix斷路器

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

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

(3).Hystrix作用

[1].服務降級

  Hystrix服務降級,其實就是線程池中單個線程障處理,防止單個線程請求時間太長,導致資源長期被佔有而得不到釋放,從而導致線程池被快速佔用完,導致服務崩潰。

  Hystrix能解決如下問題:

①.請求超時降級,線程資源不足降級,降級之後可以返回自定義數據

②.線程池隔離降級,分佈式服務可以針對不同的服務使用不同的線程池,從而互不影響

③.自動觸發降級與恢復

④.實現請求緩存和請求合併

[2].服務熔斷

  熔斷模式:這種模式主要是參考電路熔斷,如果一條線路電壓過高,保險絲會熔斷,防止火災。放到我們的系統中,如果某個目標服務調用慢或者有大量超時,此時,熔斷該服務的調用,對於後續調用請求,不在繼續調用目標服務,直接返回,快速釋放資源。如果目標服務情況好轉則恢復調用。

[3].服務限流

  限流模式主要是提前對各個類型的請求設置最高的QPS閾值,若高於設置的閾值則對該請求直接返回,不再調用後續資源。這種模式不能解決服務依賴的問題,只能解決系統整體資源分配問題,因爲沒有被限流的請求依然有可能造成雪崩效應。

[4].接近實時的監控

(4).官方文檔

  https://github.com/Netflix/Hystrix/wiki/How-To-Use

2.服務熔斷

 

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

(1).創建工程

  新建microservicecloud-provider-dept-hystrix-8001

 

 

  將microservicecloud-provider-dept-8001下的package和applicaiton.yml配置文件複製到microservicecloud-provider-dept-hystrix-8001上。

 

(2).配置pom文件

  修改部分:

<!--  hystrix -->

<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-hystrix</artifactId>

</dependency>

  完整部分:

<?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.hosystem</groupId>

        <version>1.0-SNAPSHOT</version>

    </parent>

    <modelVersion>4.0.0</modelVersion>

 

    <artifactId>microservicecloud-provider-dept-hystrix-8001</artifactId>

    <dependencies>

        <!-- 引入自己定義的api通用包,可以使用Dept部門Entity -->

        <dependency>

            <groupId>com.hosystem</groupId>

            <artifactId>microservicecloud-api</artifactId>

            <version>${project.version}</version>

        </dependency>

        <!-- 將微服務provider側註冊進eureka -->

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-eureka</artifactId>

        </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>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-jetty</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>

        </dependency>

        <!-- 修改後立即生效,熱部署 -->

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>springloaded</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-devtools</artifactId>

        </dependency>

        <!--  hystrix -->

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-hystrix</artifactId>

        </dependency>

    </dependencies>

 

</project>

(3).修改applicaiton.yml

server:

  port: 8001

 

mybatis:

  config-location: classpath:mybatis/mybatis.cfg.xml        # mybatis配置文件所在路徑

  type-aliases-package: com.hosytem.springcloud.entities    # 所有Entity別名類所在包

  mapper-locations:

  - classpath:mybatis/mapper/**/*.xml                       # mapper映射文件

 

#name spring.application.name=microservicecloud-dept   很重要很重要很重要

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.188.188:3306/cloudDB01              # 數據庫名稱

    username: root

    password: 123456

    dbcp2:

      min-idle: 5                                           # 數據庫連接池的最小維持連接數

      initial-size: 5                                       # 初始化連接數

      max-total: 5                                          # 最大連接數

      max-wait-millis: 200                                  # 等待連接獲取的最大超時時間

 

eureka:

  client: #客戶端註冊進eureka服務列表內

    service-url:

#      defaultZone: http://localhost:7001/eureka

      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

  instance:

    instance-id: microservicecloud-dept8001-hystrix   #自定義服務名稱信息

    prefer-ip-address: true     #訪問路徑可以顯示IP地址

info:

  app.name: hosystem-microservicecloud

  company.name: www.hosystem.com

  build.artifactId: $project.artifactId$

  build.version: $project.version$

(4).修改DeptController

 

package com.hosystem.springcloud.controller;

 

import com.hosystem.springcloud.entities.Dept;

import com.hosystem.springcloud.service.DeptService;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.cloud.client.ServiceInstance;

import org.springframework.cloud.client.discovery.DiscoveryClient;

import org.springframework.web.bind.annotation.*;

 

import java.util.List;

 

 

@RestController

public class DeptController

{

 

    @Autowired

    private DeptService service = null;

 

    @RequestMapping(value="/dept/get/{id}",method=RequestMethod.GET)

    //一旦調用服務方法失敗並拋出了錯誤信息後,會自動調用@HystrixCommand標註好的fallbackMethod調用類中的指定方法

    @HystrixCommand(fallbackMethod = "processHystrix_Get")

    public Dept get(@PathVariable("id") Long id)

    {

        Dept dept =  this.service.get(id);

        if(null == dept)

        {

            throw new RuntimeException("該ID:"+id+"沒有沒有對應的信息");

        }

        return dept;

    }

 

    public Dept processHystrix_Get(@PathVariable("id") Long id)

    {

        return new Dept().setDeptno(id)

                .setDname("該ID:"+id+"沒有沒有對應的信息,null--@HystrixCommand")

                .setDb_source("no this database in MySQL");

    }

}

(5).修改主啓動類

  修改DeptProvider8001_App主啓動類。

package com.hosystem.springcloud;

 

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;

import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

 

@SpringBootApplication

@EnableEurekaClient //本服務啓動後會自動註冊進eureka服務中

@EnableDiscoveryClient

@EnableCircuitBreaker//對hystrixR熔斷機制的支持

public class DeptProvider8001_Hystrix_App

{

    public static void main(String[] args)

    {

        SpringApplication.run(DeptProvider8001_Hystrix_App.class, args);

    }

}

(6).測試

[1].啓動eureka7001、eureka7002、eureka7003

[2].啓動DeptProvider8001_Hystrix_App

[3].啓動microservicecloud-consumer-dept-80

 

 

[4].訪問

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

 

3.服務降級

 

  整體資源不足於應對當前的困難,則選擇性關掉某些服務,優先提供重要的服務。

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

(1).修改microservicecloud-api

  修改microservicecloud-api工程,根據已經有的DeptClientService接口新建一個實現了FallbackFactory接口的類DeptClientServiceFallbackFactor。

 

package com.hosystem.springcloud.service;

 

import com.hosystem.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 Dept get(long id)

            {

                return new Dept().setDeptno(id)

                        .setDname("該ID:"+id+"沒有沒有對應的信息,Consumer客戶端提供的降級信息,此刻服務Provider已經關閉")

                        .setDb_source("no this database in MySQL");

            }

            @Override

            public List<Dept> list()

            {

                return null;

            }

            @Override

            public boolean add(Dept dept)

            {

                return false;

            }

        };

    }

}

(2).修改DeptClientService接口

  修改microservicecloud-api工程,DeptClientService接口在註解@FeignClient中添加fallbackFactory屬性值。

 

package com.hosystem.springcloud.service;

 

import com.hosystem.springcloud.entities.Dept;

import org.springframework.cloud.netflix.feign.FeignClient;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

 

import java.util.List;

 

//@FeignClient(value = "MICROSERVICECLOUD-DEPT")

@FeignClient(value = "MICROSERVICECLOUD-DEPT",fallbackFactory=DeptClientServiceFallbackFactory.class)

public interface DeptClientService

{

    @RequestMapping(value = "/dept/get/{id}",method = RequestMethod.GET)

    public Dept get(@PathVariable("id") long id);

 

    @RequestMapping(value = "/dept/list",method = RequestMethod.GET)

    public List<Dept> list();

 

    @RequestMapping(value = "/dept/add",method = RequestMethod.POST)

    public boolean add(Dept dept);

}

(3).mvn clean和mvn install

  對microservicecloud-api工程進行mvn clean install

 

(4).修改microservicecloud-consumer-dept-feign

  microservicecloud-consumer-dept-feign工程修改YML

server:

  port: 80

feign:

  hystrix:

    enabled: true

eureka:

  client:

    register-with-eureka: false

    service-url:

      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/

(5).測試

[1].啓動eureka7001、eureka7002、eureka7003

[2].啓動microservicecloud-provider-dept-8001

 

[3].啓動microservicecloud-consumer-dept-feign

 

[4].訪問測試

①.正常測試

http://localhost/consumer/dept/get/1

 

②.關閉服務測試

  關閉微服務microservicecloud-provider-dept-8001。

http://localhost/consumer/dept/get/1

 

  此時服務端provider已經down了,但是我們做了服務降級處理,讓客戶端在服務端不可用時也會獲得提示信息而不會掛起耗死服務器。

4.服務監控hystrixDashboard

 

  除了隔離依賴服務的調用以外,Hystrix還提供了準實時的調用監控(Hystrix Dashboard),Hystrix會持續地記錄所有通過Hystrix發起的請求的執行信息,並以統計報表和圖形的形式展示給用戶,包括每秒執行多少請求多少成功,多少失敗等。Netflix通過hystrix-metrics-event-stream項目實現了對以上指標的監控。Spring Cloud也提供了Hystrix Dashboard的整合,對監控內容轉化成可視化界面。

(1).新建工程

  新建工程microservicecloud-consumer-hystrix-dashboard

 

 

(2).修改pom

  修改部分:

   <!-- hystrix和 hystrix-dashboard相關-->

   <dependency>

       <groupId>org.springframework.cloud</groupId>

       <artifactId>spring-cloud-starter-hystrix</artifactId>

   </dependency>

   <dependency>

       <groupId>org.springframework.cloud</groupId>

       <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>

   </dependency>

  完整部分:

<?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.hosystem</groupId>

        <version>1.0-SNAPSHOT</version>

    </parent>

    <modelVersion>4.0.0</modelVersion>

 

    <artifactId>microservicecloud-consumer-hystrix-dashboard</artifactId>

    <dependencies>

        <!-- 自己定義的api -->

        <dependency>

            <groupId>com.hosystem</groupId>

            <artifactId>microservicecloud-api</artifactId>

            <version>${project.version}</version>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-web</artifactId>

        </dependency>

        

        <!-- 修改後立即生效,熱部署 -->

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>springloaded</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-devtools</artifactId>

        </dependency>

 

        <!-- Ribbon相關 -->

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-eureka</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-ribbon</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-config</artifactId>

        </dependency>

 

        <!-- feign相關 -->

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-feign</artifactId>

        </dependency>

 

        <!-- hystrix和 hystrix-dashboard相關-->

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-hystrix</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>

        </dependency>

    </dependencies>

</project>

(3).配置applicaiton.yml

server:

  port: 9001

(4).配置主啓動類

  新建主啓動類DeptConsumer_DashBoard_App,然後添加註解@EnableHystrixDashboard.

package com.hosystem.springcloud;

 

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;

 

@SpringBootApplication

@EnableHystrixDashboard

public class DeptConsumer_DashBoard_App

{

    public static void main(String[] args)

    {

        SpringApplication.run(DeptConsumer_DashBoard_App.class,args);

    }

}

(5).配置provider監控依賴

  所有Provider微服務提供類(8001/8002/8003)都需要監控依賴配置.

   <!-- actuator監控信息完善 -->

   <dependency>

     <groupId>org.springframework.boot</groupId>

     <artifactId>spring-boot-starter-actuator</artifactId>

   </dependency>

(6).啓動項目

[1].啓動dashboard

  啓動microservicecloud-consumer-hystrix-dashboard該微服務監控消費端。

http://localhost:9001/hystrix

 

[2].啓動eureka

  啓動eureka7001、eureka7002、eureka7003

 

[3].啓動hystrix

  啓動microservicecloud-provider-dept-hystrix-8001

 

http://localhost:8001/dept/get/1

http://localhost:8001/hystrix.stream

  

(7).監控測試

  多次刷新http://localhost:8001/dept/get/1,然後通過Hystrix Dashboard查看。

[1].填寫監控地址

http://localhost:8001/hystrix.stream

 

  Delay:該參數用來控制服務器上輪詢監控信息的延遲時間,默認爲2000毫秒,可以通過配置該屬性來降低客戶端的網絡和CPU消耗。

  Title:該參數對應了頭部標題Hystrix Stream之後的內容,默認會使用具體監控實例的URL,可以通過配置該信息來展示更合適的標題。

[2].監控結果

  7色、1圈、1線

 

  實心圓:共有兩種含義。它通過顏色的變化代表了實例的健康程度,它的健康度從綠色<黃色<橙色<紅色遞減。該實心圓除了顏色的變化之外,它的大小也會根據實例的請求流量發生變化,流量越大該實心圓就越大。所以通過該實心圓的展示,就可以在大量的實例中快速的發現故障實例和高壓力實例

  曲線:用來記錄2分鐘內流量的相對變化,可以通過它來觀察到流量的上升和下降趨勢。

 

[3].複雜監控結果

 

 

參考文檔:

https://github.com/Netflix/Hystrix/wiki/How-To-Use

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章