跳閘了啊! 服務容災:熔斷器簡介


雪崩效應

現如今SOA、微服務風愈演愈烈,越來越多的業務和資源被以服務的形式包裝和發布,服務間又可能會依賴其他各種服務。由此而來不可避免的會產生很多問題。

比如一個服務,其依賴了另外30個服務。假設每個服務的可用率都有三個9(99.9%),那么我們計算一下:

99.99%^30 = 99.7%

現實很殘酷,這個服務的實際可用性只能是99.7%,也就是說每個月這個服務都要好宕機8000+秒~~~


正常用戶請求時,服務內部依次請求A\P\H\I服務,兵返回響應結果。


非常不幸,我們的I服務出了某些問題,此時我們的用戶請求就被堵塞在I服務處。


更加悲劇的是,后續越來越多的請求都被堵塞在I服務處,而這些被堵塞的請求會占用線程、IO、網絡等系統資源,隨着資源被占用的越來越多,本來不存在的性能問題也會隨之而來,造成系統中的其他服務出現問題,甚至導致系統奔潰。

這也就是我們常說的雪崩效應


服務容災

為了避免出現服務的雪崩,我們需要對服務做容災處理。

常規的服務容災處理思路有:

  • 資源隔離
  • 超時設定
  • 服務降級
  • 服務限流

其中每種思路又可以有不同的解決方案。

比如資源隔離可以通過將不同的服務發布在獨立的docker容器或服務器中,這樣即使一個服務出現問題,也不會殃及池魚。

服務降級和服務限流可以通過前端nginx+lua來實現,當服務處理延遲或宕機時,nginx可以直接返回固定的降級/失敗響應,已快速跳過問題服務。


Hystrix

Hystrix,是Netflix的一個開源熔斷器,通過Hystrix,我們可以很方便的實現資源隔離、限流、超時設計、服務降級等服務容災措施,並且還提供了強大的監控,可以查看各個熔斷器的允許情況。

通過上圖,可以看出,Hystrix提供了一個HystrixCommand用來包裝調用請求。HystrixCommand的執行流程大概如下:
1.首先檢查緩存中是否有結果。如果有則直接返回緩存結果。
2.判斷斷路器是否開啟,如果斷路器閉合,執行降級業務邏輯並返回降級結果。
3.判斷信號量/線程池資源是否飽和,如飽和則執行降級業務邏輯並返回降級結果。
4.調用實際服務,如發生異常,執行降級業務邏輯並返回降級結果,並調整斷路器閾值。
5.判斷實際業務是否超時,超時則返回超時響應結果,並調整斷路器閾值。

了解了流程,來看下如何使用Hystrix。首先我們需要定義一個命令類來包裝我們的業務調用:

//繼承HystrixCommand
public class CommandHelloFailure extends HystrixCommand<String> {

    private final String name;

    public CommandHelloFailure(String name) {
		//設置分組key,分組key可以用在報表、監控中,默認的線程池隔離也基於分組key
         super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
			//指定命令key,可
            .andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld"))
			//指定線程池key,取代默認的分組key
            .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")));
		/*
		//線程池隔離模式,不寫默認是線程池隔離模式
		HystrixCommandProperties.Setter()
		   .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD)
		//信號量隔離模式
		HystrixCommandProperties.Setter()
		   .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)
		//超時時間,默認1秒
		HystrixCommandProperties.Setter()
		   .withExecutionTimeoutInMilliseconds(int value)  
		//信號量模式下,最大並發請求限流,默認值10
		HystrixCommandProperties.Setter()
		   .withFallbackIsolationSemaphoreMaxConcurrentRequests(int value)  
		//熔斷器閾值,默認20
		HystrixCommandProperties.Setter()
			.withCircuitBreakerRequestVolumeThreshold(int value)
		//熔斷器關閉時間,默認5秒
		HystrixCommandProperties.Setter()
			.withCircuitBreakerSleepWindowInMilliseconds(int value)
		*/
        this.name = name;
    }

    @Override
	//執行實際服務,這里模擬全部返回異常
    protected String run() {
        throw new RuntimeException("this command always fails");
    }

    @Override
	//執行降級業務
    protected String getFallback() {
        return "Hello Failure " + name + "!";
    }

	@Override
	//從緩存中獲取
    protected String getCacheKey() {
        ...
    }
} 

使用這個命令類也非常簡單:

//同步執行
String s = new CommandHelloWorld("Bob").execute();
//異步執行
Future<String> s = new CommandHelloWorld("Bob").queue();
//響應式
Observable<String> s = new CommandHelloWorld("Bob").observe();

通過Hystrix提供的監控界面,我們可以觀察到各個熔斷器的執行情況:

更多說明和例子可以查看Hystrix的wiki


Hystrix和Spring boot

想在spring boot中使用Hystrix就更加簡單了,只需要引入spring-cloud-starter-hystrix,

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

然后添加注解使用Hystrix
@EnableCircuitBreaker
@EnableHystrixDashboard

最后在需要使用熔斷器的地方標記注解即可。

@HystrixCommand(groupKey = "xxx", fallbackMethod = "yyy")
public String doSomething() 

遙想2015年9月7日,上交所、深交所、中金所宣布,擬在保留現有個股漲跌幅制度前提下,引入指數熔斷機制。隨后A股聯系兩天下跌熔斷,提前收盤。其中這里的熔斷機制和我們今天討論的熔斷器思路一致,但是反而導致了A股暴跌,這也說明了我們還是得從根源產出高可用的服務,而不是依賴某些外部措施幫助我們提高可用性。同時說明了A股比咱寫的垃圾服務更加不可靠,還是安心當個碼農吧。

最后,就問各位童鞋,敢不敢點個贊~~~~

參考資料:
https://github.com/Netflix/Hystrix
http://www.cnblogs.com/jesse2013/p/things-architect-must-know.html


免責聲明!

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



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