傳統項目利用Hystrix實現熱點接口的服務隔離


 這段時間接了個需求,需要在我目前負責的數據系統上加個接口,主要是實現用戶行為的記錄。前端對接的項目主要有公司的PC,WAP,WEIXIN,APP等,每個端大概有兩台左右的負載。因為目前我的這個項目主要是面向內部,負責數據運營相關的內容,是個單體項目。如果線上各個接入點不做限制,瞬間大量的並發進入必然會導致目前項目的崩潰,其他的功能也無法正常使用。

1、需求分析

通過前期的需求分析,目前線上系統無法進行限流處理,所以最終解決問題還是要從接口入手。

目前我對接口的處理有兩種實現方案:

  1. 可以利用MQ實現消息的錯峰,將消息發送到MQ服務器。
  2. 實現對接口的隔離限流,避免當前接口對其他功能的影響。

其實我認為最好的實現方案就是第一種了,可以保證消息的准確送達,避免並發資源的占用。不過,因為公司條件的限制暫時不能新增中間件,所以只能在現有系統上進行改造,最后只能采用第二種方法了。

2、Hystrix的簡單介紹

官方的定義就不說了,這里簡單說下我的理解。Hystrix作為斷路器主要是實現對服務的容錯保護,簡單來說就是服務隔離、服務降級、服務熔斷,服務限流這幾項。

舉個常見的例子,當你某寶【搶購】一個產品時,經常會彈出[網絡錯誤,請重試。]的提示,這種時候是真的網絡問題嗎?顯示不是。這種情況下其實是對調用的接口進行了降級處理,當降級的次數或比例達到一定的條件后,斷路器就會直接打開,之后的訪問就會直接降級,而不會判斷是否降級了。達到對服務的容錯保護以及給用戶友好提示的目的。詳細的流程可以看下圖。

一般Hystrix的容錯保護在微服務中是用在客戶端,也就是調用方。而我這次實際上是用在了提供方,主要是前台的項目我無法控制,只能在接口上想方法了。目前我使用Hystrix的主要目的就是實現對服務的隔離和限流,而對降級和熔斷反而不是特別的關心,當然實際的使用要結合場景。

因為一般Tomcat默認是一個線程池150個線程,如果單個熱點接口的請求過多,就會造成其他功能沒有線程可用甚至直接程序崩潰的問題。Hystrix的服務隔離主要有兩種,常用的就是線程池隔離的方式,對熱點接口建立單獨的線程池避免對主程序的影響。另一種是信號量的方式,用的場景不是太多。兩者的區別其實就是一個增大系統的開銷,一個則直接限制了線程總的並發數,開銷更小一些。

Hystrix服務調用邏輯圖

3、項目中的應用實現

 本文是在傳統Spring項目中的應用,Springboot中的相關配置和依賴有稍許的不同。

maven依賴:

     <!-- hystrix -->
        <dependency>
            <groupId>com.netflix.hystrix</groupId>
            <artifactId>hystrix-core</artifactId>
            <version>1.5.9</version>
        </dependency>
        <dependency>
            <groupId>com.netflix.hystrix</groupId>
            <artifactId>hystrix-metrics-event-stream</artifactId>
            <version>1.5.9</version>
        </dependency>
        <dependency>
            <groupId>com.netflix.hystrix</groupId>
            <artifactId>hystrix-javanica</artifactId>
            <version>1.5.9</version>
        </dependency>

 在Spring的配置文件中配置Hystrix的切面信息

    <bean id="hystrixAspect" class="com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect"></bean>
    <aop:aspectj-autoproxy />

主要是開啟注解的AOP掃描,這里我們可以在這個類的源碼中看到實現

 可以看到我們主要是通過這個類切面掃描Hystrix的相關注解,以達到接口處理前,提前執行Hystrix相關邏輯的代碼。

/**
 * 提供客戶行為接口
 *
 */
@Controller
@RequestMapping(value = "/test")
public class BehaviorController {
    Logger                                logger    = Logger.getLogger(BehaviorController.class);
    @Autowired
    private BehaviorService behaviorService;

    @RequestMapping(value="/addBehavior",method = RequestMethod.POST,produces = "application/json;charset=UTF-8")
    @ResponseBody
    @HystrixCommand(fallbackMethod = "fallback", threadPoolProperties = {  
            @HystrixProperty(name = "coreSize", value = "20"), @HystrixProperty(name = "maxQueueSize", value = "100"),
            @HystrixProperty(name = "queueSizeRejectionThreshold", value = "20")},
            commandProperties = {  
                    @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "30000"),  
                    @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20")
  
    })
    public String addBehavior(@RequestBody String parms) {

            //業務邏輯實現
            return result;
    }

    public String fallback(@RequestBody String parms){
        logger.info("fallback");
        //失敗的實現
        return result;
    }
}    

注意:
請求的接口必須為public,fallback為降級的接口邏輯,可以為private,也可以為public。

但是要特別注意fallback方法的返回值和參數必須和請求方法相同

另外需要說的是,當請求失敗、被拒絕、超時或者斷路器打開時,都會進入回退方法,但是進入回退方法並不意味着斷路器已經被打開。

4、常用參數的介紹

參數

描述

默認值

execution.isolation.strategy

隔離策略,有THREAD和SEMAPHORE

THREAD - 它在單獨的線程上執行,並發請求受線程池中的線程數量的限制
SEMAPHORE - 它在調用線程上執行,並發請求受到信號量計數的限制

默認使用THREAD模式,以下幾種場景可以使用SEMAPHORE模式:

只想控制並發度

外部的方法已經做了線程隔離

調用的是本地方法或者可靠度非常高、耗時特別小的方法(如medis)

 

execution.isolation.thread.timeoutInMilliseconds

超時時間

默認值:1000

在THREAD模式下,達到超時時間,可以中斷

在SEMAPHORE模式下,會等待執行完成后,再去判斷是否超時

設置標准:

有retry,99meantime+avg meantime

沒有retry,99.5meantime

 

execution.timeout.enabled

HystrixCommand.run()執行是否應該有超時。

默認值:true

fallback.isolation.semaphore.maxConcurrentRequests

設置在使用時允許執行fallback方法的最大並發請求數

默認值:10

circuitBreaker.requestVolumeThreshold

設置滾動時間窗中,斷路器熔斷的最小請求數

 默認值:20

滾動窗口默認10s,即10s內失敗請求達到20個,熔斷器即打開

 coreSize

設置執行命令線程池的核心線程數。

 默認值:10

maxQueueSize

設置執行命令線程池的核心線程數。

  默認值:-1

當設置為-1時,線程池使用SynchronousQueue實現的隊列,否則將使用LinkedBlockingQueue實現的隊列

queueSizeRejectionThreshold

為隊列設置拒絕閾值

默認值:5

當設置該參數后,即使隊列沒有達到最大值也能拒絕請求。

注意:當maxQueueSize屬性為-1的時候,該屬性不會生效

另外需要特別注意的是:fallback的屬性maxConcurrentRequests,當請求達到了最大並發數時,后續的請求將會被拒絕並拋出異常(因為它已經沒有后續的fallback可以被調用了),異常信息一般為com.netflix.hystrix.exception.HystrixRuntimeException: xxxxxxx fallback execution rejected.

更多參數見官方文檔:https://github.com/Netflix/Hystrix/wiki/Configuration

另外附一個網友翻譯的文檔:https://blog.csdn.net/tongtong_use/article/details/78611225

5、接口測試

並發接口測試的方法很多,可以寫代碼,也可以用apache batch以及jmeter等工具。以常用的jmeter為例,測試本接口。

設置環境變量:
JMETER_HOME   D:\apache-jmeter-3.0
CLASSPATH     %JMETER_HOME%\lib\ext\ApacheJMeter_core.jar;%JMETER_HOME%\lib\jorphan.jar;%JMETER_HOME%\lib/logkit-2.0.jar;

新建線程組:

設置並發參數:

第一個參數為線程數,第二個參數為啟動時間,第三個參數為請求次數。以上述配置為例即為1秒內啟動50個線程,每個線程請求一次。

添加HTTP請求

這里設置請求的路徑,參數等等。

設置請求頭信息,因人而異

我的設置:Content-Type:application/json

表格查看結果

 

 查看結果:

 這個可以根據機器的性能進行測試,以我的接口為例,當設置並發數為100以內時,基本上不會有降級處理,當並發數大於100時,就會有部分請求進入降級接口了。

6、接口監控

實際項目中,經常需要對我們的接口和項目情況進行監控,Hystrix已經為我們考慮到了。Hystrix提供了近乎實時的監控,Hystrix會實時的,累加的記錄所有關於HystrixCommand的執行信息,包括執行了每秒執行了多少請求,多少成功,多少失敗等等,更多指標請查看:https://github.com/Netflix/Hystrix/wiki/Metrics-and-Monitoring

在web.xml中添加下述配置:

    <!-- for Hystrix -->
    <servlet>
        <display-name>HystrixMetricsStreamServlet</display-name>
        <servlet-name>HystrixMetricsStreamServlet</servlet-name>
        <servlet-class>com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>HystrixMetricsStreamServlet</servlet-name>
        <url-pattern>/hystrix.stream</url-pattern>
    </servlet-mapping>

啟動應用。訪問http://hostname:port/項目名/hystrix.stream,可以看到下面信息

這種是最原生的監控使用方式,大家可以另外集成Hystrix 提供的一個 Dashboard 應用。Dashboard 是一個單獨的應用,我們可以獨立部署。如果需要監控整個 Hystrix 集群,就需要使用 Turbine 應用。Turbine 也是 Netflix 開源的一個服務。但是使用 Hystrix Stream 和 Turbine 存在一個明顯的不足,那就是無法查看歷史的監控數據。解決這個問題就需要我們自己來實現了。

監控的相關不是本文的重點,就不多介紹了,大家可以百度下hystrix在微服務項目中監控的實現,這里網上文章很多,基本上和傳統項目沒有任何區別了,大家可以參考實現。


免責聲明!

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



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