【SpringCloud】【Hoxton】Hystrix全面解析

01 基礎環境準備
02 一文讀懂Eureka
03 Zookeeper註冊中心
04 Consule註冊中心
05 Ribbon
06 OpenFegin
07 Hystrix全面解析
08 Gateway全面解析
09 Config配置中心
10 Bus消息總線

1 分佈式系統面臨的問題

複雜分佈式體系結構中的應用程序有數十個依賴關係,每個依賴關係在某些時候將不可避免地失敗。
在這裏插入圖片描述
左圖中的請求需要調用A,P,H,I 四個服務,如果一切順利則沒有什麼問題,關鍵是如果I服務超時會出現什麼情況呢?
在這裏插入圖片描述
(2) 雪崩
多個微服務之間調用的時候,假設微服務A調用微服務B和微服務C,微服務B和微服務C又調用其它的微服務,這就是所謂的“扇出"。如果扇出的鏈路上某個微服務的調用響應時間過長或者不可用,對微服務A的調用就會佔用越來越多的系統資源,進而引起系統崩潰,所謂的“雪崩效應”。所以通常當你發現一個模塊下的某個實例失敗後,這時候這個模塊依然還會接收流量,然後這個有問題的模塊還調用了其他的模塊,這樣就會發生級聯故障,或者叫雪崩。

2 Hystrix是什麼

在這裏插入圖片描述
Hystrix是個用於處理分佈式系統的延遲和容錯的開源庫,在分佈式奈統裏,許多依賴不可避免的會調用失敗,比如超時、異常等。Hystrix能夠保證在一個依賴出問題的情況下,不會導致整體服務失敗,避免級聯故障,以提高分佈式系統的彈性。“斷路器”本身是一種開關裝置,當某個服務單元發生故障之後,通過斷路器的故障監控(類似熔斷保險絲),向調用方返回個符合預期的、可處理的備選響應( Fallback),而不是長時間的等待或者拋出調用方無法處理的異常,這樣就保證了服務調用方的線程不會被長時間、不必要地佔用,從而避免了故障在分佈式系統中的蔓延,乃至雪崩。

(1) 服務降級
當服務器壓力劇增的情況下,根據實際業務情況及流量,對一些服務和頁面有策略的不處理或換種簡單的方式處理,從而釋放服務器資源以保證核心交易正常運作或高效運作。

使用場景:服務異常、超時、服務熔斷觸發服務降級、線程池/信號量打滿也會導致服務降級

(2) 服務熔斷
高壓電路中,如果某個地方的電壓過高,熔斷器就會熔斷,對電路進行保護。股票交易中,如果股票指數過高,也會採用熔斷機制,暫停股票的交易。同樣,在微服務架構中,熔斷機制也是起着類似的作用。當扇出鏈路的某個微服務不可用或者響應時間太長時,會進行服務的降級,進而熔斷該節點微服務的調用,快速返回錯誤的響應信息。當檢測到該節點微服務調用響應正常後,恢復調用鏈路。

(3) 服務限流
限流的目的是通過對併發訪問/請求進行限速或者一個時間窗口內的的請求進行限速來保護系統,一旦達到限制速率則可以拒絕服務(定向到錯誤頁或告知資源沒有了)、排隊或等待(比如秒殺、評論、下單)、降級(返回兜底數據或默認數據,如商品詳情頁庫存默認有貨)。

3 新建工程 provider-hystrix

在這裏插入圖片描述

(1) pom

<dependencies>
    <!--hystrix-->
    <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-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </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>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <dependency>
        <groupId>com.zrs.springcloud</groupId>
        <artifactId>commons</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

(2) application.yml

server:
  port: 7004
spring:
  application:
    name: provider-hystrix
eureka:
  client:
    #是否將自己註冊到EurekaServer
    register-with-eureka: true
    #是否從EurekaServer獲取已有的註冊服務
    fetch-registry: true
    #註冊地址
    service-url:
      defaultZone: http://localhost:7000/eureka/
  instance:
    instance-id: provider-hystrix
    prefer-ip-address: true

(3) 主啓動類

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

(4) Controller

@RestController
@RequestMapping("/hystrix")
public class HystrixController {
    @GetMapping("/hello")
    public String hello(){
        return "Hello Thread:"+Thread.currentThread().getName();
    }
    @GetMapping("/threeseconds")
    public String threeseconds(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "hello threeseconds";
    }
}

(5) 啓動 測試
在這裏插入圖片描述
在這裏插入圖片描述

4 新建工程customer-hystrix

在這裏插入圖片描述

4.1 pom

<dependencies>
    <!--hystrix-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    <!--eureka 客戶端-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!--oepn fegin-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</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-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </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>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <dependency>
        <groupId>com.zrs.springcloud</groupId>
        <artifactId>commons</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
</dependencies>

4.2 application.yml

server:
  port: 8004
spring:
  application:
    name: customer-hystrix
eureka:
  client:
    #是否將自己註冊到EurekaServer
    register-with-eureka: true
    #是否從EurekaServer獲取已有的註冊服務
    fetch-registry: true
    #註冊地址
    service-url:
      defaultZone: http://localhost:7000/eureka/
  instance:
    instance-id: customer-hystrix
    prefer-ip-address: true

4.3 主程序啓動

@SpringBootApplication
@EnableFeignClients
public class HystrixCustomerApplication {
    public static void main(String[] args) {
        SpringApplication.run(HystrixCustomerApplication.class);
            }
}

4.4 FeginService


@Component
@FeignClient("PROVIDER-HYSTRIX")
@RequestMapping("/hystrix")
public interface FeginService {
 
    @GetMapping("/hello")
    String hello();
   
    @GetMapping("/threeseconds")
    String threeseconds();
}

4.5 controller

@RequestMapping("/customer")
@RestController
public class HystrixController {

    @Autowired
    private FeginService feginService;


    @GetMapping("/hello")
    public String hello(){
        return  feginService.hello();
    }


    @GetMapping("/threeseconds")
    public String threeseconds(){
        return feginService.threeseconds();
    }

}

4.6 啓動

在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述

5 降級配置

5.1 provider-hystrix配置

(1) 修改HystrixController

@RestController
@RequestMapping("/hystrix")
public class HystrixController {
    @GetMapping("/hello")
    public String hello(){
        return "Hello Thread:"+Thread.currentThread().getName();
    }
    /**
     * fallbackMethod 降級方法
     * timeoutInMilliseconds: 2秒爲正常響應,超過兩秒調用降級方法
     *
     */
    @HystrixCommand(fallbackMethod = "fallbackMethod",commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
    })
    @GetMapping("/threeseconds")
    public String threeseconds(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "hello threeseconds";
    }
    public String fallbackMethod(){
        return "服務器正忙,請稍後訪問。Thread:"+Thread.currentThread().getName();
    }
}

(2) 修改啓動類

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

(3) 測試
在這裏插入圖片描述

5.2 customer-hystrix降級配置

(1) application.yml添加配置文件

#開啓降級
feign:
  hystrix:
    enabled: true

(2) 修改主啓動類

@SpringBootApplication
@EnableFeignClients
@EnableHystrix
public class HystrixCustomerApplication {
    public static void main(String[] args) {
        SpringApplication.run(HystrixCustomerApplication.class);
    }
}

(3) 修改HystrixController

@RequestMapping("/customer")
@RestController
public class HystrixController {

    @Autowired
    private FeginService feginService;

    @GetMapping("/hello")
    public String hello(){
        return  feginService.hello();
    }

    @HystrixCommand(fallbackMethod = "fallbackMethod",commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
    })

    @GetMapping("/threeseconds")
    public String threeseconds(){
        return feginService.threeseconds();
    }

    public String fallbackMethod(){
        return "服務器正忙,請稍後訪問。Thread:"+Thread.currentThread().getName();
    }
}

(4) 重啓運行
在這裏插入圖片描述

6 hystrix降級解耦

6.1 @DefaultProperties

(1) DefaultProperties作用:全局降級方法。修改customer-hystrix的HystrixController

/**
* @Description: @DefaultProperties全局降級方法
* @Auther: zhurongsheng
* @Date: 2020/3/14 22:32
*/
@RequestMapping("/customer")
@RestController
@DefaultProperties(defaultFallback = "commonfallbackMethod")
public class HystrixController {
    @Autowired
    private FeginService feginService;
    @GetMapping("/hello")
    public String hello(){
        return  feginService.hello();
    }
    @HystrixCommand(commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
    })
    @GetMapping("/threeseconds")
    public String threeseconds(){
        return feginService.threeseconds();
    }
    public String commonfallbackMethod(){
        return "服務器正忙,請稍後訪問。Thread:"+Thread.currentThread().getName();
    }
}

(2) 重啓,測試
在這裏插入圖片描述

6.2 customer-hystrix配置文件分離

(1) FeginService

@FeignClient(value = "PROVIDER-HYSTRIX",fallback = FeginFallbackService.class,path = "/hystrix")
@Service
public interface FeginService {
 
    @GetMapping("/hello")
    String hello();

    @GetMapping("/threeseconds")
    String threeseconds();
}

(2) 接口實現類,FeginFallbackService

@Service
public class FeginFallbackService implements FeginService{
    @Override
    public String hello() {
        return "FeginFallbackService invoke hello";
    }
    @Override
    public String threeseconds() {
        return "FeginFallbackService invoke threeseconds";
    }
}

(3) 修改Controller,HystrixController

@RequestMapping("/customer")
@RestController
public class HystrixController {
   
    @Autowired
    private FeginService feginService;
   
    @GetMapping("/hello")
    public String hello(){
        return  feginService.hello();
    }
  
    @HystrixCommand(commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "2000")
    })
    @GetMapping("/threeseconds")
    public String threeseconds(){
        return feginService.threeseconds();
    }
}

(4) 重啓測試
在這裏插入圖片描述

7 熔斷

服務熔斷:在一定週期內,服務異常次數達到設定的閾值或百分比,則觸發熔斷,熔斷後,後面的請求將都走默認處理方法defaultFallback

7.1 修改provider-hystrix的 HystrixController

@RestController
@RequestMapping("/hystrix")
public class HystrixController {
    @GetMapping("/hello")
    public String hello() {
        return "Hello Thread:" + Thread.currentThread().getName();
    }
    /**
     * fallbackMethod 降級方法
     * timeoutInMilliseconds: 2秒爲正常響應,超過兩秒調用降級方法
     */
    @HystrixCommand(fallbackMethod = "fallbackMethod", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000")
    })
    @GetMapping("/threeseconds")
    public String threeseconds() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "hello threeseconds";
    }
    public String fallbackMethod() {
        return "服務器正忙,請稍後訪問。Thread:" + Thread.currentThread().getName();
    }
    /**
     * =====================熔斷配置=======================
     * circuitBreaker.enabled: 啓動熔斷
     * circuitBreaker.requestVolumeThreshold:請求次數
     * circuitBreaker.errorThresholdPercentage: 失敗率達到多少啓動熔斷
     */
    @HystrixCommand(fallbackMethod = "circuitBreakerFallback",commandProperties = {
            @HystrixProperty(name="circuitBreaker.enabled",value = "true"),
            @HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "10"),
            @HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")
    })
    @GetMapping("/{id}")
    public String circuitBreaker(@PathVariable("id") Integer id) {
        if (id<0){
            throw  new RuntimeException("id ="+id+",不能爲負數");
        }
        return "調用成功,O(∩_∩)O~  id=" + id;
    }
    public String circuitBreakerFallback(@PathVariable("id") Integer id) {
        return "id =" + id + ", 不能爲負數,o(╥﹏╥)o~ ";
    }
}

7.2 啓動觀察

(1) 正常訪問
在這裏插入圖片描述
(2) 錯誤訪問
在這裏插入圖片描述
(3) 多次錯誤訪問後
在這裏插入圖片描述

8 服務監控hystrixDashboard

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

8.1 pom

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</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-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
</dependencies>

8.2 application.yml

server:
  port: 9001

8.3 啓動類,並啓動

@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashbordApplication {
    public static void main(String[] args) {
        SpringApplication.run(HystrixDashbordApplication.class);
    }
}

8.4 訪問

在這裏插入圖片描述

8.5 在provider-hystrix裏添加HystrixConfig配置文件,重啓服務

@Configuration
public class HystrixConfig {
    @Bean
    public ServletRegistrationBean myServlet(){
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }
}

8.6 dashboard添加provider-hystrix

http://localhost:7004/hystrix.stream

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述

GITHUB

#分支 Hystrix-enviroment-release-v1.0
https://github.com/zhurongsheng666/spring-cloud-hoxton
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章