SpringCloud學習之Hystrix


一、為什么要有斷路器

  在分布式系統當中,服務之間調用關系會隨着業務的發展而變的復雜,一個服務可能依賴多個服務,服務之間層層依賴也是家常便飯的事情,如果一個服務的癱瘓很有可能導致整個系統的崩潰。比如說,現在每棟房子,每家每戶都有電閘,電閘的作用是保證有一家用電出現異常時,電閘進行斷電跳閘的操作,這樣不至於導致整棟樓用電癱瘓,那么我們的系統也是如此:我們請看下圖:

  

  

這個系統架構中由於服務I的異常(可能是程序運行錯誤,可能是系統阻塞,可能是負載過重等等),漸漸的導致整個系統崩潰,我們稱之為雪崩效應

 

二、關於Hystrix

  1. Hystrix對應的中文名字是“豪豬”,豪豬周身長滿了刺,能保護自己不受天敵的傷害,代表了一種防御機制,Hystrix提供了熔斷、隔離、Fallback、cache、監控等功能,能夠在一個、或多個依賴同時出現問題時保證系統依然可用。
  2. Hystrix通過四個方面的機制來解決這個問題
    • 隔離(線程池隔離和信號量隔離):限制調用分布式服務的資源使用,某一個調用的服務出現問題不會影響其他服務調用。線程隔離:每個服務都為一個個獨立的線程組,當I服務出現問題時,不會導致整個服務癱瘓。由於線程隔離會帶來線程開銷,有些場景(比如無網絡請求場景)可能會因為用開銷換隔離得不償失,為此hystrix提供了信號量隔離,當服務的並發數大於信號量閾值時將進入fallback。

      隔離策略示例圖

      

    • 優雅的降級機制:超時降級、資源不足時(線程或信號量)降級,降級總之是一種退而求其次的方式,根據業務場景的不同,一般采用以下兩種模式進行降級:第一種(最常用)如果服務失敗,則我們通過fallback進行降級,返回靜態值。第二種:調用備選方案
    • 融斷:當失敗率達到閥值自動觸發降級(如因網絡故障/超時造成的失敗率高),熔斷器觸發的快速失敗會進行快速恢復。類似於電閘

      

    • 緩存:提供了請求緩存、請求合並實現。
    • 支持實時監控、報警、控制(修改配置)

 

三、Hystrix使用方法

  3.1)繼承HystrixCommand類,重寫run方法與getFallBack方法,簡單的代碼示例:

package com.bdqn.lyrk.springcloud.order.hystrix;

import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;

public class HelloWorldHystrix extends HystrixCommand<String> {

    public HelloWorldHystrix() {
        super(HystrixCommandGroupKey.Factory.asKey("first"));
    }

    @Override
    protected String run() throws Exception {
        //Thread.sleep(10000);
        System.out.println("running...");
       // System.out.println(1 / 0);
        return "running...";
    }

    @Override
    protected String getFallback() {
        System.out.println("error running...");
        return "error running...";
    }
}
View Code

 

  3.2)  設置信號量隔離策略,初次接觸設置屬性的代碼比較復雜,更多的可以參考wiki

public HelloWorldHystrix() {
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("first"))
                        .andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
                        .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE))
                        .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withQueueSizeRejectionThreshold(10))
                        .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionIsolationSemaphoreMaxConcurrentRequests(10))
                        .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withFallbackIsolationSemaphoreMaxConcurrentRequests(50))
        );
    }
View Code

 

  3.3)針對於3.2,我們可以創建如下線程進行調用:

 

for (int i = 0; i < 50; i++) {
            new Thread(() -> {
                HelloWorldHystrix helloWorldHystrix = new HelloWorldHystrix();
                helloWorldHystrix.execute();
            }).start();

        }
View Code

 

 四。spring-cloud中使用Hystrix

  4.1) 添加相關依賴

  

compile('org.springframework.cloud:spring-cloud-starter-hystrix')
compile('org.springframework.cloud:spring-cloud-starter-hystrix-dashboard')

  4.2) 在啟動類上添加 @EnableCircuitBreaker與@EnableHystrixDashboard注解

  

package com.bdqn.lyrk.springcloud.order;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;

@SpringBootApplication
@EnableEurekaServer
@EnableCircuitBreaker
@EnableHystrixDashboard
public class OrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}
View Code

 

  4.3)添加@HystrixCommand注解

  

package com.bdqn.lyrk.springcloud.order.controller;

import com.bdqn.lyrk.service.api.IOrderService;
import com.bdqn.lyrk.service.dto.OrderDTO;
import com.bdqn.lyrk.springcloud.order.config.StudentConfig;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
@RefreshScope
public class OrderController {

    @Autowired
    private StudentConfig studentConfig;

    @Autowired
    private IOrderService orderService;

    @GetMapping("/getInfo")
    public String getInfo() {
        return studentConfig.getName() + ":" + studentConfig.getAge();
    }

    @GetMapping("/orderId/{orderId}")
    @HystrixCommand(fallbackMethod = "getFailedOrder", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
            , @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "2")
    })
    public OrderDTO getOrderById(@PathVariable("orderId") Integer orderId) throws InterruptedException {
        TimeUnit.SECONDS.sleep(orderId);
        return orderService.getOrderById(orderId);
    }

    public OrderDTO getFailedOrder(Integer orderId) {
        OrderDTO orderDTO = new OrderDTO();
        orderDTO.setOrderName("失敗的訂單");
        return orderDTO;
    }
}
View Code

 

  注意其中有兩個關鍵屬性分別為:

   execution.isolation.thread.timeoutInMilliseconds 這個是請求最大的響應時間

   circuitBreaker.requestVolumeThreshold 如果執行失敗的次數等於或者超過這個值就開啟保護

 

  4.4)當我們的系統添加actutator時,我們可以訪問請求地址:http://localhost:8001/health 來檢測狀態

  此時我們通過http://localhost:8001/orderId/4訪問三次服務得到如下結果

 

  注意,此時斷路器打開保護機制

  4.5)使用Hystrix的儀表盤

    還記得我們添加 spring-cloud-starter-netflix-hystrix-dashboard的依賴么?通過訪問http://localhost:8001/hystrix就可以得到如下界面

 

 

 

 

  


免責聲明!

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



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