現現在SOA、微服務風愈演愈烈,愈來愈多的業務和資源被以服務的形式包裝和發佈,服務間又可能會依賴其餘各類服務。由此而來不可避免的會產生不少問題。html
好比一個服務,其依賴了另外30個服務。假設每一個服務的可用率都有三個9(99.9%),那麼咱們計算一下:前端
99.99%^30 = 99.7%nginx
現實很殘酷,這個服務的實際可用性只能是99.7%,也就是說每月這個服務都要好宕機8000+秒~~~git
正經常使用戶請求時,服務內部依次請求A\P\H\I服務,兵返回響應結果。github
很是不幸,咱們的I服務出了某些問題,此時咱們的用戶請求就被堵塞在I服務處。spring
更加悲劇的是,後續愈來愈多的請求都被堵塞在I服務處,而這些被堵塞的請求會佔用線程、IO、網絡等系統資源,隨着資源被佔用的愈來愈多,原本不存在的性能問題也會隨之而來,形成系統中的其餘服務出現問題,甚至致使系統奔潰。docker
這也就是咱們常說的雪崩效應緩存
爲了不出現服務的雪崩,咱們須要對服務作容災處理。服務器
常規的服務容災處理思路有:網絡
其中每種思路又能夠有不一樣的解決方案。
好比資源隔離能夠經過將不一樣的服務發佈在獨立的docker容器或服務器中,這樣即便一個服務出現問題,也不會殃及池魚。
服務降級和服務限流能夠經過前端nginx+lua來實現,當服務處理延遲或宕機時,nginx能夠直接返回固定的降級/失敗響應,已快速跳過問題服務。
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。
想在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