欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring Cloud Hystrix入門和Hystrix命令原理分析

 更新時間:2018年08月29日 09:37:24   作者:舊光影里的少年  
這篇文章主要介紹了Spring Cloud Hystrix入門和Hystrix命令原理分析,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

斷路由器模式

在分布式架構(gòu)中,當(dāng)某個服務(wù)單元發(fā)生故障之后,通過斷路由器的故障監(jiān)控(類似熔斷保險絲),向調(diào)用方返回一個錯誤響應(yīng),而不是長時間的等待。這樣就不會使得線程因調(diào)用故障服務(wù)被長時間占用不釋放,避免了故障在分布式系統(tǒng)中的蔓延。

Spring Cloud Hystrix針對上述問題實現(xiàn)了斷路由器、線程隔離等一系列服務(wù)保護(hù)功能。它是基于Netflix Hystrix實現(xiàn),該框架的目標(biāo)在于通過控制那些訪問遠(yuǎn)程系統(tǒng)、服務(wù)和第三方庫的節(jié)點(diǎn),從而對延遲和故障提供更強(qiáng)大的容錯能力。

Hystrix具備服務(wù)降級、服務(wù)熔斷、線程和信號隔離、請求緩存、請求合并以及服務(wù)監(jiān)控等強(qiáng)大功能。

快速入門

構(gòu)建一個如下架構(gòu)圖的服務(wù)調(diào)用關(guān)系

分析上述架構(gòu)圖,主要有以下幾項工作:

  • eureka-server工程: 服務(wù)注冊中心,端口1111hello-service工程:
  • HELLO-SERVICE服務(wù)單元,啟動兩個實例,端口分別為8081和8082
  • ribbon-consumer工程: 使用Ribbon實現(xiàn)的服務(wù)消費(fèi)者,端口9000

修改ribbon-consumer模塊

修改pom.xml

首先在pom.xml文件中增加spring-cloud-starter-hystrix依賴

開啟斷路由器功能

在ribbon-consumer主類中使用@EnableCircuitBreaker注解開啟斷路由器功能,在這里還有一個小技巧,可以使用@SpringCloudApplicationd代替@EnableCircuitBreaker、@EnableEurekaClient、@SpringBootApplication這三個注解。

改造服務(wù)消費(fèi)方式

改造ribbon-consumer中的HelloService,如下

package cn.sh.ribbon.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

/**
 * @author sh
 */
@Service
public class HelloService {

  private static final Logger logger = LoggerFactory.getLogger(HelloService.class);

  @Autowired
  private RestTemplate restTemplate;

  /**
   * 使用@HystrixCommand注解指定回調(diào)方法
   * @param name
   * @return
   */
  @HystrixCommand(fallbackMethod = "ribbonHelloFallback", commandKey = "helloKey")
  public String ribbonHello(String name) {
    long start = System.currentTimeMillis();
    String result = restTemplate.getForObject("http://HELLO-SERVICE/hello?name=" + name, String.class);
    long end = System.currentTimeMillis();
    logger.info("Spend Time:" + (end - start));
    return result;
  }

  public String ribbonHelloFallback() {
    return "Hello, this is fallback";
  }
}

改造服務(wù)提供者

改造hello-service模塊中的HelloService.java,如下:

package cn.sh.hello.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.Random;

/**
 * @author sh
 */
@Service
public class HelloService {

  private static final Logger logger = LoggerFactory.getLogger(HelloService.class);

  public String hello(String name) throws InterruptedException {
    int sleepTime = new Random().nextInt(3000);
    logger.info("sleepTime:" + sleepTime);
    Thread.sleep(sleepTime);
    return "Hello, " + name;
  }
}

在服務(wù)提供者的改造中,我們會讓方法阻塞幾秒中返回內(nèi)容,由于Hystrix默認(rèn)的超時時間為2000ms,在這里產(chǎn)生0-3000的隨機(jī)數(shù)可以讓處理過程有一定概率觸發(fā)斷路由器。

原理分析


下面根據(jù)工作流程圖,我們來分析一下Hystrix是如何工作的。

第1步 創(chuàng)建HystrixCommand或HystrixObservableCommand對象

首先,構(gòu)建一個HystrixCommand或HystrixObservableCommand對象,用來表示對依賴服務(wù)的操作請求,同時傳遞所有需要的參數(shù)。這兩個對象都采用了命令模式來實現(xiàn)對服務(wù)調(diào)用操作的封裝,但是這兩個對象分別針對不同的應(yīng)用場景。

HystrixCommand: 用在依賴的服務(wù)返回單個操作結(jié)果的時候HystrixObservableCommand: 用在依賴的服務(wù)返回多個操作結(jié)果的時候

命令模式,將來自客戶端的請求封裝成一個對象,從而讓你可以使用不同的請求對客戶端進(jìn)行參數(shù)化。它可以用于實現(xiàn)行為請求者和行為實現(xiàn)者的解耦,以便使兩者可以適應(yīng)變化

命令模式的示例代碼在command模塊下

通過命令模式的示例代碼可以分析出命令模式的幾個關(guān)鍵點(diǎn):

  1. Receiver: 接收者,處理具體的業(yè)務(wù)邏輯
  2. Command: 抽象命令,定義了一個對象應(yīng)具備的一系列命令操作,如execute()、undo()、redo()等。當(dāng)命令操作被調(diào)用的時候就會觸發(fā)接收者做具體命令對應(yīng)的業(yè)務(wù)邏輯。
  3. ConcreteCommand: 具體的命令實現(xiàn),在這里要綁定命令操作和接收者之間的關(guān)系,execute()命令的實現(xiàn)轉(zhuǎn)交給了Receiver的action()方法
  4. Invoker: 調(diào)用者,它擁有一個命令對象,可以在需要時通過命令對象完成具體的業(yè)務(wù)邏輯

命令模式中Invoker和Receiver的關(guān)系非常類似于請求-響應(yīng)模式,所以它比較適用于實現(xiàn)記錄日志、撤銷操作、隊列請求等。

以下情況我們可以考慮使用命令模式:

  1. 使用命令模式作為回調(diào)在面向?qū)ο笙到y(tǒng)中的替代。
  2. 需要在不同的時間指定請求、將請求排隊。一個命令對象和原先的請求發(fā)出者可以有不同的生命周期。換言之,原先的請求發(fā)出者可能已經(jīng)不在了,但是命令本身仍然是活動的。這時命令的接收者可以是在本地,也可以在網(wǎng)絡(luò)的另一個地址。命令對象可以在序列化之后傳送到另一臺機(jī)器上。
  3. 系統(tǒng)需要支持命令的撤銷。命令對象可以把狀態(tài)存儲起來,等到客戶端需要撤銷命令所產(chǎn)生的效果時,可以調(diào)用undo()方法,把命令所產(chǎn)生的效果撤銷掉。命令對象還提供redo()方法,以供客戶端在需要時再重新實施命令效果。
  4. 如果要將系統(tǒng)中所有的數(shù)據(jù)更新到日志里,以便在系統(tǒng)崩潰時,可以根據(jù)日志讀回所有的數(shù)據(jù)更新命令,重新調(diào)用execute()方法一條一條執(zhí)行這些命令,從而恢復(fù)系統(tǒng)在崩潰前所做的數(shù)據(jù)更新。

第2步 命令執(zhí)行

從圖中我們可以看到一共存在4種命令的執(zhí)行方式,Hystrix在執(zhí)行時會根據(jù)創(chuàng)建的Command對象以及具體的情況來選擇一個執(zhí)行。

HystrixCommand

HystrixCommand實現(xiàn)了兩個執(zhí)行方式:

  1. execute(): 同步執(zhí)行,從依賴的服務(wù)返回一個單一的結(jié)果對象,或是在錯誤時拋出異常
  2. queue(): 異步執(zhí)行,直接返回一個Future對象,其中包含了服務(wù)執(zhí)行結(jié)束時要返回的單一結(jié)果對象。
R value = command.execute();
Future<R> fValue = command.queue();

HystrixObservableCommand

HystrixObservableCommand實現(xiàn)了另兩種執(zhí)行方式:

  • observer(): 返回Observable對象,它代表了操作的多個結(jié)果,是一個HotObservable
  • toObservable(): 同樣返回Observable對象,也代表操作的多個結(jié)果,返回的是一個ColdObservable
Observable<R> ohvalue = command.observe();
Observable<R> ocvalue = command.toObservable();

Hot Observable和Cold Observable,分別對應(yīng)了上面command.observe()和command.toObservable的返回對象。

Hot Observable,不論事件源是否有訂閱者,都會在創(chuàng)建后對事件進(jìn)行發(fā)布,所以對Hot Observable的每一個訂閱者都有可能是從事件源的中途開始的,并可能只是看到了整個操作的局部過程。

Cold Observable在沒有訂閱者的時候不會發(fā)布事件,而是進(jìn)行等待,直到有訂閱者后才會發(fā)布事件,所以對于Cold Observable的訂閱者,它可以保證從一開始看到整個操作的全部過程。

HystrixCommand也使用RxJava實現(xiàn):

  1. execute():該方法是通過queue()返回的異步對象Future<R>的get()方法來實現(xiàn)同步執(zhí)行的。該方法會等待任務(wù)執(zhí)行結(jié)束,然后獲得R類型的結(jié)果返回。
  2. queue():通過toObservable()獲得一個Cold Observable,并且通過通過toBlocking()將該Observable轉(zhuǎn)換成BlockingObservable,它可以把數(shù)據(jù)以阻塞的方式發(fā)出來,toFuture方法則是把BlockingObservable轉(zhuǎn)換為一個Future,該方法只是創(chuàng)建一個Future返回,并不會阻塞,這使得消費(fèi)者可以自己決定如何處理異步操作。execute()則是直接使用了queue()返回的Future中的阻塞方法get()來實現(xiàn)同步操作的。
  3. 通過這種方式轉(zhuǎn)換的Future要求Observable只發(fā)射一個數(shù)據(jù),所以這兩個實現(xiàn)都只能返回單一結(jié)果。

RxJava觀察者-訂閱者模式入門介紹

在Hystrix的底層實現(xiàn)中大量使用了RxJava。上面提到的Observable對象就是RxJava的核心內(nèi)容之一,可以把Observable對象理解為事件源或是被觀察者,與其對應(yīng)的是Subscriber對象,可以理解為訂閱者或是觀察者。

  1. Observable用來向訂閱者Subscriber對象發(fā)布事件,Subscriber對象在接收到事件后對其進(jìn)行處理,這里所指的事件通常就是對依賴服務(wù)的調(diào)用。
  2. 一個Observable可以發(fā)出多個事件,直到結(jié)束或是發(fā)生異常。
  3. Observable對象每發(fā)出一個事件,就會調(diào)用對應(yīng)觀察者Subscriber對象的onNext()方法。
  4. 每一個Observable的執(zhí)行,最后一定會通過調(diào)用Subscriber.onCompleted()或是Subscriber.onError()來結(jié)束該事件的操作流。

第3步 結(jié)果是否被緩存

若當(dāng)前命令的請求緩存功能是被啟用的,并且該命令緩存命中,那么緩存的結(jié)果會立即以O(shè)bservable對象的形式返回。

第4步 斷路器是否打開

在命令結(jié)果沒有緩存命中的時候,Hystrix在執(zhí)行命令前需要檢查斷路器是否為打開狀態(tài):

如果斷路器是打開的,Hystrix不會執(zhí)行命令,而是直接賺到fallback處理邏輯(對應(yīng)下面第8步)

如果斷路器是關(guān)閉的,那么Hystrix會跳到第5步,檢查是否有可用資源來執(zhí)行命令。

第5步 線程池/請求隊列/信號量是否占滿

如果與命令相關(guān)的線程池和請求隊列或者信號量(不使用線程池的時候)已被占滿,那么Hystrix不會執(zhí)行命令,轉(zhuǎn)接到fallback處理邏輯(對應(yīng)下面第8步)

Hystrix所判斷的線程池并非容器的線程池,而是每個依賴服務(wù)的專有線程池。Hystrix為了保證不會因為某個依賴服務(wù)的問題影響到其他依賴服務(wù)而采用了艙壁模式來隔離每個依賴的服務(wù)。

第6步 HystrixObservableCommand.construct()或HystrixCommand.run()

Hystrix會根據(jù)我們編寫的方法來決定采取什么樣的方式去請求依賴服務(wù):

  1. HystrixCommand.run(): 返回一個單一的結(jié)果,或者拋出異常
  2. HystrixObservableCommand.construct(): 返回一個Observable對象來發(fā)射多個結(jié)果,或通過onError發(fā)送錯誤通知

如果run()或construct()方法的執(zhí)行時間超過了命令設(shè)置的超時閥值,當(dāng)前處理線程會拋出一個TimeoutException(如果該命令不在其自身的線程中執(zhí)行,則會通過單獨(dú)的計時線程拋出)。在這種情況下,Hystrix會轉(zhuǎn)到fallback邏輯去處理(第8步)。同時,如果當(dāng)前命令沒有被取消或中斷,那么它最終會忽略run()或construct()方法的返回。

如果命令沒有拋出異常并返回了結(jié)果,那么Hystrix在記錄一些日志并采集監(jiān)控報告之后將該結(jié)果返回。在使用run()時,返回一個Observable,它會發(fā)射單個結(jié)果并產(chǎn)生onCompleted的結(jié)束通知,在使用construct()時,會直接返回該方法產(chǎn)生的Observable對象。

第7步 計算斷路器的健康度

Hystrix會將成功、失敗、拒絕、超時等信息報告給斷路器,斷路器會維護(hù)一組計數(shù)器來統(tǒng)計這些數(shù)據(jù)。

斷路器會使用這些統(tǒng)計數(shù)據(jù)來決定是否要將斷路器打開,來對某個依賴服務(wù)的請求進(jìn)行熔斷/短路,直到恢復(fù)期結(jié)束。若在恢復(fù)期結(jié)束后,根據(jù)統(tǒng)計數(shù)據(jù)判斷如果還是未達(dá)到健康指標(biāo),就再次熔斷/短路。

第8步 fallback處理

當(dāng)命令執(zhí)行失敗時,Hystrix會進(jìn)入fallback嘗試回退處理,我們通常也稱之為服務(wù)降級。能夠引起服務(wù)降級處理的情況主要有以下幾種:

  1. 第4步,當(dāng)前命令處于熔斷/短路狀態(tài),斷路器是打開的時候。
  2. 第5步,當(dāng)前命令的線程池、請求隊列或者信號量被占滿的時候。
  3. 第6步,HystrixObservableCommand.construct()或HystrixCommand.run()拋出異常的時候。

在服務(wù)降級邏輯中,我們需要實現(xiàn)一個通用的響應(yīng)結(jié)果,并且該結(jié)果的處理邏輯應(yīng)當(dāng)是從緩存或是根據(jù)一些靜態(tài)邏輯來獲取,而不是依賴網(wǎng)絡(luò)請求獲取。如果一定要在降級邏輯中包含網(wǎng)絡(luò)請求,那么該請求也必須被包裝在HystrixCommand或是HystrixObservableCommand中,從而形成級聯(lián)的降級策略,而最終的降級邏輯一定不是一個依賴網(wǎng)絡(luò)請求的處理,而是一個能夠穩(wěn)定返回結(jié)果的處理邏輯。

HystrixCommand和HystrixObservableCommand中實現(xiàn)降級邏輯時有以下不同:

  1. 當(dāng)使用HystrixCommand的時候,通過實現(xiàn)HystrixCommand.getFallback()來實現(xiàn)服務(wù)降級邏輯。
  2. 當(dāng)使用HystrixObservableCommand的時候,通過HystrixObservableCommand.resumeWithFallback()實現(xiàn)服務(wù)降級邏輯,該方法會返回一個Observable對象來發(fā)射一個或多個降級結(jié)果。

當(dāng)命令的降級邏輯返回結(jié)果之后,Hystrix就將該結(jié)果返回給調(diào)用者。當(dāng)使用HystrixCommand.getFallback()時候,它會返回一個Observable對象,該對象會發(fā)射getFallback()的處理結(jié)果。而使用HystrixObservableCommand.resumeWithFallback()實現(xiàn)的時候,它會將Observable對象直接返回。

如果我們沒有為命令實現(xiàn)降級邏輯或在降級處理中拋出了異常,Hystrix依然會返回一個Observable對象,但是他不會發(fā)射任何結(jié)果數(shù)據(jù),而是通過onError方法通知命令立即中斷請求,并通過onError()方法將引起命令失敗的異常發(fā)送給調(diào)用者。在降級策略的實現(xiàn)中我們應(yīng)盡可能避免失敗的情況。

如果在執(zhí)行降級時發(fā)生失敗,Hystrix會根據(jù)不同的執(zhí)行方法作出不同的處理:

  1. execute(): 拋出異常
  2. queue(): 正常返回Future對象,但是調(diào)用get()來獲取結(jié)果時會拋出異常
  3. observe(): 正常返回Observable對象,當(dāng)訂閱它的時候,將立即通過訂閱者的onError方法來通知中止請求
  4. toObservable(): 正常返回Observable對象,當(dāng)訂閱它的時候,將通過調(diào)用訂閱者的onError方法來通知中止請求

第9步 返回成功的響應(yīng)

當(dāng)Hystrix命令執(zhí)行成功之后,它會將處理結(jié)果直接返回或是以O(shè)bservable的形式返回。具體的返回形式取決于不同的命令執(zhí)行方式。

  1. toObservable(): 返回原始的Observable,必須通過訂閱它才會真正觸發(fā)命令的執(zhí)行流程
  2. observe(): 在toObservable()產(chǎn)生原始Observable之后立即訂閱它,讓命令能夠馬上開始異步執(zhí)行,并返回一個Observable對象,當(dāng)調(diào)用它的subscribe時,將重新產(chǎn)生結(jié)果和通知給訂閱者。
  3. queue(): 將toObservable()產(chǎn)生的原始Observable通過toBlocking()方法轉(zhuǎn)換成BlockingObservable對象,并調(diào)用它的toFuture()方法返回異步的Future對象
  4. execute(): 在queue()產(chǎn)生異步結(jié)果Future對象之后,通過調(diào)用get()方法阻塞并等待結(jié)果的返回。

代碼地址

spring-cloud-example

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 用Set類判斷Map里key是否存在的示例代碼

    用Set類判斷Map里key是否存在的示例代碼

    本篇文章主要是對用Set類判斷Map里key是否存在的示例代碼進(jìn)行了介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2013-12-12
  • 解決IDEA service層跳轉(zhuǎn)實現(xiàn)類的快捷圖標(biāo)消失問題

    解決IDEA service層跳轉(zhuǎn)實現(xiàn)類的快捷圖標(biāo)消失問題

    這篇文章主要介紹了解決IDEA service層跳轉(zhuǎn)實現(xiàn)類的快捷圖標(biāo)消失問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • 在Mac OS上安裝Java以及配置環(huán)境變量的基本方法

    在Mac OS上安裝Java以及配置環(huán)境變量的基本方法

    這篇文章主要介紹了在Mac OS上安裝Java以及配置環(huán)境變量的基本方法,包括查看所安裝Java版本的方法,需要的朋友可以參考下
    2015-10-10
  • Java?設(shè)計模式中的命令模式詳情

    Java?設(shè)計模式中的命令模式詳情

    這篇文章主要介紹了Java?設(shè)計模式中的命令模式詳情,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的朋友可以參考一下
    2022-07-07
  • Spring整合Quartz Job以及Spring Task的實現(xiàn)方法

    Spring整合Quartz Job以及Spring Task的實現(xiàn)方法

    下面小編就為大家分享一篇Spring整合Quartz Job以及Spring Task的實現(xiàn)方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2017-12-12
  • 淺談Java內(nèi)存泄露

    淺談Java內(nèi)存泄露

    內(nèi)存泄漏(Memory Leak)是指程序中己動態(tài)分配的堆內(nèi)存由于某種原因程序未釋放或無法釋放,造成系統(tǒng)內(nèi)存的浪費(fèi),導(dǎo)致程序運(yùn)行速度減慢甚至系統(tǒng)崩潰等嚴(yán)重后果。下面我們來一起了解如何解決
    2019-05-05
  • Java異常報錯:java.nio.file.FileSystemException的多種解決方案

    Java異常報錯:java.nio.file.FileSystemException的多種解決方案

    在Java應(yīng)用程序中處理文件和目錄時,java.nio.file.FileSystemException是一個常見的異常,這個異常發(fā)生在嘗試進(jìn)行文件系統(tǒng)操作時,本文將詳細(xì)探討FileSystemException的成因,并提供多種解決方案,需要的朋友可以參考下
    2024-12-12
  • SpringBoot自定義starter方式

    SpringBoot自定義starter方式

    本文介紹了如何創(chuàng)建一個自定義的Spring Boot Starter,以實現(xiàn)日志功能,通過使用SPI機(jī)制,可以在不修改啟動類的情況下,實現(xiàn)自動配置和功能導(dǎo)入,同時,還討論了如何在自定義Starter中編寫必要的配置文件和注解,以確保功能的正確實現(xiàn)和配置的智能提示
    2025-02-02
  • Java中的CompletableFuture基本用法

    Java中的CompletableFuture基本用法

    這篇文章主要介紹了Java中的CompletableFuture基本用法,CompletableFuture是java.util.concurrent庫在java 8中新增的主要工具,同傳統(tǒng)的Future相比,其支持流式計算、函數(shù)式編程、完成通知、自定義異常處理等很多新的特性,需要的朋友可以參考下
    2024-01-01
  • idea下如何設(shè)置項目啟動的JVM運(yùn)行內(nèi)存大小

    idea下如何設(shè)置項目啟動的JVM運(yùn)行內(nèi)存大小

    這篇文章主要介紹了idea下如何設(shè)置項目啟動的JVM運(yùn)行內(nèi)存大小問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12

最新評論