摘要:前言分布式系統(tǒng)中經(jīng)常會出現(xiàn)某個基礎(chǔ)服務(wù)不可用造成整個系統(tǒng)不可用的情況這種現(xiàn)象被稱為服務(wù)雪崩效應(yīng)為了應(yīng)對服務(wù)雪崩一種常見的做法是手動服務(wù)降級而的出現(xiàn)給我們提供了另一種選擇服務(wù)雪崩效應(yīng)的定義服務(wù)雪崩效應(yīng)是一種因服務(wù)提供者的不可用導(dǎo)致服務(wù)調(diào)用者的
前言
分布式系統(tǒng)中經(jīng)常會出現(xiàn)某個基礎(chǔ)服務(wù)不可用造成整個系統(tǒng)不可用的情況, 這種現(xiàn)象被稱為服務(wù)雪崩效應(yīng). 為了應(yīng)對服務(wù)雪崩, 一種常見的做法是手動服務(wù)降級. 而Hystrix的出現(xiàn),給我們提供了另一種選擇.
服務(wù)雪崩效應(yīng)的定義服務(wù)雪崩效應(yīng)是一種因 服務(wù)提供者 的不可用導(dǎo)致 服務(wù)調(diào)用者 的不可用,并將不可用 逐漸放大 的過程.如果所示:
上圖中, A為服務(wù)提供者, B為A的服務(wù)調(diào)用者, C和D是B的服務(wù)調(diào)用者. 當A的不可用,引起B(yǎng)的不可用,并將不可用逐漸放大C和D時, 服務(wù)雪崩就形成了.
服務(wù)雪崩效應(yīng)形成的原因我把服務(wù)雪崩的參與者簡化為 服務(wù)提供者 和 服務(wù)調(diào)用者, 并將服務(wù)雪崩產(chǎn)生的過程分為以下三個階段來分析形成的原因:
服務(wù)提供者不可用
重試加大流量
服務(wù)調(diào)用者不可用
服務(wù)雪崩的每個階段都可能由不同的原因造成, 比如造成 服務(wù)不可用 的原因有:
硬件故障
程序Bug
緩存擊穿
用戶大量請求
硬件故障可能為硬件損壞造成的服務(wù)器主機宕機, 網(wǎng)絡(luò)硬件故障造成的服務(wù)提供者的不可訪問.
緩存擊穿一般發(fā)生在緩存應(yīng)用重啟, 所有緩存被清空時,以及短時間內(nèi)大量緩存失效時. 大量的緩存不命中, 使請求直擊后端,造成服務(wù)提供者超負荷運行,引起服務(wù)不可用.
在秒殺和大促開始前,如果準備不充分,用戶發(fā)起大量請求也會造成服務(wù)提供者的不可用.
而形成 重試加大流量 的原因有:
用戶重試
代碼邏輯重試
在服務(wù)提供者不可用后, 用戶由于忍受不了界面上長時間的等待,而不斷刷新頁面甚至提交表單.
服務(wù)調(diào)用端的會存在大量服務(wù)異常后的重試邏輯.
這些重試都會進一步加大請求流量.
最后, 服務(wù)調(diào)用者不可用 產(chǎn)生的主要原因是:
同步等待造成的資源耗盡
當服務(wù)調(diào)用者使用 同步調(diào)用 時, 會產(chǎn)生大量的等待線程占用系統(tǒng)資源. 一旦線程資源被耗盡,服務(wù)調(diào)用者提供的服務(wù)也將處于不可用狀態(tài), 于是服務(wù)雪崩效應(yīng)產(chǎn)生了.
服務(wù)雪崩的應(yīng)對策略針對造成服務(wù)雪崩的不同原因, 可以使用不同的應(yīng)對策略:
流量控制
改進緩存模式
服務(wù)自動擴容
服務(wù)調(diào)用者降級服務(wù)
流量控制 的具體措施包括:
網(wǎng)關(guān)限流
用戶交互限流
關(guān)閉重試
因為Nginx的高性能, 目前一線互聯(lián)網(wǎng)公司大量采用Nginx+Lua的網(wǎng)關(guān)進行流量控制, 由此而來的OpenResty也越來越熱門.
用戶交互限流的具體措施有: 1. 采用加載動畫,提高用戶的忍耐等待時間. 2. 提交按鈕添加強制等待時間機制.
改進緩存模式 的措施包括:
緩存預(yù)加載
同步改為異步刷新
服務(wù)自動擴容 的措施主要有:
AWS的auto scaling
服務(wù)調(diào)用者降級服務(wù) 的措施包括:
資源隔離
對依賴服務(wù)進行分類
不可用服務(wù)的調(diào)用快速失敗
資源隔離主要是對調(diào)用服務(wù)的線程池進行隔離.
我們根據(jù)具體業(yè)務(wù),將依賴服務(wù)分為: 強依賴和若依賴. 強依賴服務(wù)不可用會導(dǎo)致當前業(yè)務(wù)中止,而弱依賴服務(wù)的不可用不會導(dǎo)致當前業(yè)務(wù)的中止.
不可用服務(wù)的調(diào)用快速失敗一般通過 超時機制, 熔斷器 和熔斷后的 降級方法 來實現(xiàn).
使用Hystrix預(yù)防服務(wù)雪崩Hystrix [h?st"r?ks]的中文含義是豪豬, 因其背上長滿了刺,而擁有自我保護能力. Netflix的 Hystrix 是一個幫助解決分布式系統(tǒng)交互時超時處理和容錯的類庫, 它同樣擁有保護系統(tǒng)的能力.
Hystrix的設(shè)計原則包括:
資源隔離
熔斷器
命令模式
資源隔離貨船為了進行防止漏水和火災(zāi)的擴散,會將貨倉分隔為多個, 如下圖所示:
這種資源隔離減少風(fēng)險的方式被稱為:Bulkheads(艙壁隔離模式).
Hystrix將同樣的模式運用到了服務(wù)調(diào)用者上.
在一個高度服務(wù)化的系統(tǒng)中,我們實現(xiàn)的一個業(yè)務(wù)邏輯通常會依賴多個服務(wù),比如:
商品詳情展示服務(wù)會依賴商品服務(wù), 價格服務(wù), 商品評論服務(wù). 如圖所示:
調(diào)用三個依賴服務(wù)會共享商品詳情服務(wù)的線程池. 如果其中的商品評論服務(wù)不可用, 就會出現(xiàn)線程池里所有線程都因等待響應(yīng)而被阻塞, 從而造成服務(wù)雪崩. 如圖所示:
Hystrix通過將每個依賴服務(wù)分配獨立的線程池進行資源隔離, 從而避免服務(wù)雪崩.
如下圖所示, 當商品評論服務(wù)不可用時, 即使商品服務(wù)獨立分配的20個線程全部處于同步等待狀態(tài),也不會影響其他依賴服務(wù)的調(diào)用.
熔斷器模式定義了熔斷器開關(guān)相互轉(zhuǎn)換的邏輯:
服務(wù)的健康狀況 = 請求失敗數(shù) / 請求總數(shù).
熔斷器開關(guān)由關(guān)閉到打開的狀態(tài)轉(zhuǎn)換是通過當前服務(wù)健康狀況和設(shè)定閾值比較決定的.
當熔斷器開關(guān)關(guān)閉時, 請求被允許通過熔斷器. 如果當前健康狀況高于設(shè)定閾值, 開關(guān)繼續(xù)保持關(guān)閉. 如果當前健康狀況低于設(shè)定閾值, 開關(guān)則切換為打開狀態(tài).
當熔斷器開關(guān)打開時, 請求被禁止通過.
當熔斷器開關(guān)處于打開狀態(tài), 經(jīng)過一段時間后, 熔斷器會自動進入半開狀態(tài), 這時熔斷器只允許一個請求通過. 當該請求調(diào)用成功時, 熔斷器恢復(fù)到關(guān)閉狀態(tài). 若該請求失敗, 熔斷器繼續(xù)保持打開狀態(tài), 接下來的請求被禁止通過.
熔斷器的開關(guān)能保證服務(wù)調(diào)用者在調(diào)用異常服務(wù)時, 快速返回結(jié)果, 避免大量的同步等待. 并且熔斷器能在一段時間后繼續(xù)偵測請求執(zhí)行結(jié)果, 提供恢復(fù)服務(wù)調(diào)用的可能.
命令模式Hystrix使用命令模式(繼承HystrixCommand類)來包裹具體的服務(wù)調(diào)用邏輯(run方法), 并在命令模式中添加了服務(wù)調(diào)用失敗后的降級邏輯(getFallback).
同時我們在Command的構(gòu)造方法中可以定義當前服務(wù)線程池和熔斷器的相關(guān)參數(shù). 如下代碼所示:
public class Service1HystrixCommand extends HystrixCommand{ private Service1 service; private Request request; public Service1HystrixCommand(Service1 service, Request request){ supper( Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ServiceGroup")) .andCommandKey(HystrixCommandKey.Factory.asKey("servcie1query")) .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("service1ThreadPool")) .andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter() .withCoreSize(20))//服務(wù)線程池數(shù)量 .andCommandPropertiesDefaults(HystrixCommandProperties.Setter() .withCircuitBreakerErrorThresholdPercentage(60)//熔斷器關(guān)閉到打開閾值 .withCircuitBreakerSleepWindowInMilliseconds(3000)//熔斷器打開到關(guān)閉的時間窗長度 )) this.service = service; this.request = request; ); } @Override protected Response run(){ return service1.call(request); } @Override protected Response getFallback(){ return Response.dummy(); } }
在使用了Command模式構(gòu)建了服務(wù)對象之后, 服務(wù)便擁有了熔斷器和線程池的功能.
下圖為Hystrix服務(wù)調(diào)用的內(nèi)部邏輯:
構(gòu)建Hystrix的Command對象, 調(diào)用執(zhí)行方法.
Hystrix檢查當前服務(wù)的熔斷器開關(guān)是否開啟, 若開啟, 則執(zhí)行降級服務(wù)getFallback方法.
若熔斷器開關(guān)關(guān)閉, 則Hystrix檢查當前服務(wù)的線程池是否能接收新的請求, 若超過線程池已滿, 則執(zhí)行降級服務(wù)getFallback方法.
若線程池接受請求, 則Hystrix開始執(zhí)行服務(wù)調(diào)用具體邏輯run方法.
若服務(wù)執(zhí)行失敗, 則執(zhí)行降級服務(wù)getFallback方法, 并將執(zhí)行結(jié)果上報Metrics更新服務(wù)健康狀況.
若服務(wù)執(zhí)行超時, 則執(zhí)行降級服務(wù)getFallback方法, 并將執(zhí)行結(jié)果上報Metrics更新服務(wù)健康狀況.
若服務(wù)執(zhí)行成功, 返回正常結(jié)果.
若服務(wù)降級方法getFallback執(zhí)行成功, 則返回降級結(jié)果.
若服務(wù)降級方法getFallback執(zhí)行失敗, 則拋出異常.
Hystrix Metrics的實現(xiàn)Hystrix的Metrics中保存了當前服務(wù)的健康狀況, 包括服務(wù)調(diào)用總次數(shù)和服務(wù)調(diào)用失敗次數(shù)等. 根據(jù)Metrics的計數(shù), 熔斷器從而能計算出當前服務(wù)的調(diào)用失敗率, 用來和設(shè)定的閾值比較從而決定熔斷器的狀態(tài)切換邏輯. 因此Metrics的實現(xiàn)非常重要.
1.4之前的滑動窗口實現(xiàn)Hystrix在這些版本中的使用自己定義的滑動窗口數(shù)據(jù)結(jié)構(gòu)來記錄當前時間窗的各種事件(成功,失敗,超時,線程池拒絕等)的計數(shù).
事件產(chǎn)生時, 數(shù)據(jù)結(jié)構(gòu)根據(jù)當前時間確定使用舊桶還是創(chuàng)建新桶來計數(shù), 并在桶中對計數(shù)器經(jīng)行修改.
這些修改是多線程并發(fā)執(zhí)行的, 代碼中有不少加鎖操作,邏輯較為復(fù)雜.
Hystrix在這些版本中開始使用RxJava的Observable.window()實現(xiàn)滑動窗口.
RxJava的window使用后臺線程創(chuàng)建新桶, 避免了并發(fā)創(chuàng)建桶的問題.
同時RxJava的單線程無鎖特性也保證了計數(shù)變更時的線程安全. 從而使代碼更加簡潔.
以下為我使用RxJava的window方法實現(xiàn)的一個簡易滑動窗口Metrics, 短短幾行代碼便能完成統(tǒng)計功能,足以證明RxJava的強大:
@Test public void timeWindowTest() throws Exception{ Observable總結(jié)source = Observable.interval(50, TimeUnit.MILLISECONDS).map(i -> RandomUtils.nextInt(2)); source.window(1, TimeUnit.SECONDS).subscribe(window -> { int[] metrics = new int[2]; window.subscribe(i -> metrics[i]++, InternalObservableUtils.ERROR_NOT_IMPLEMENTED, () -> System.out.println("窗口Metrics:" + JSON.toJSONString(metrics))); }); TimeUnit.SECONDS.sleep(3); }
通過使用Hystrix,我們能方便的防止雪崩效應(yīng), 同時使系統(tǒng)具有自動降級和自動恢復(fù)服務(wù)的效果.
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/66218.html
摘要:前言分布式系統(tǒng)中經(jīng)常會出現(xiàn)某個基礎(chǔ)服務(wù)不可用造成整個系統(tǒng)不可用的情況這種現(xiàn)象被稱為服務(wù)雪崩效應(yīng)為了應(yīng)對服務(wù)雪崩一種常見的做法是手動服務(wù)降級而的出現(xiàn)給我們提供了另一種選擇服務(wù)雪崩效應(yīng)的定義服務(wù)雪崩效應(yīng)是一種因服務(wù)提供者的不可用導(dǎo)致服務(wù)調(diào)用者的 前言 分布式系統(tǒng)中經(jīng)常會出現(xiàn)某個基礎(chǔ)服務(wù)不可用造成整個系統(tǒng)不可用的情況, 這種現(xiàn)象被稱為服務(wù)雪崩效應(yīng). 為了應(yīng)對服務(wù)雪崩, 一種常見的做法是手動服...
摘要:有一次別人的云服務(wù)器被攻擊,提供商竟然重啟了物理機然后又諸多悲劇出現(xiàn)。造成微博服務(wù)短暫不可用。通過建立工具來診斷問題,并創(chuàng)建一種復(fù)盤事故的文化來推動并作出改進,防止未來發(fā)生故障。 showImg(https://segmentfault.com/img/bV0jif?w=900&h=385); 相信小伙伴們在上網(wǎng)或者玩游戲的時候一定都遇到過無法訪問的情況。服務(wù)器炸了的原因有各種各樣,下...
摘要:棧長得到消息,停止開發(fā)了。。。是一個輕量級的容錯組件,其靈感來自于,主要為和函數(shù)式編程設(shè)計的看到這里,棧長表示學(xué)不動了。。。上面說了,官方推薦替代的開源組件,這個棧長也沒有用過,查了下,資料也比較稀少。 showImg(https://segmentfault.com/img/remote/1460000017201104?w=1600&h=1066); 棧長得到消息,Hystrix ...
摘要:服務(wù)雪崩效應(yīng)是一種因服務(wù)提供者的不可用導(dǎo)致服務(wù)消費者的不可用并將不可用逐漸放大的過程。這種代理能夠記錄最近調(diào)用發(fā)生錯誤的次數(shù),然后決定使用允許操作繼續(xù),或者立即返回錯誤。這個自己持有的上下文默認實現(xiàn)類也是。 ?????本篇集成Hystrix,繼續(xù)搭建demo。 雪崩效應(yīng):在微服務(wù)架構(gòu)中通常會有多個服務(wù)層調(diào)用,基礎(chǔ)服務(wù)的故障可能會導(dǎo)致級聯(lián)故障,進而造成整個系統(tǒng)不可用的情況,這種現(xiàn)象被稱為...
閱讀 3079·2021-11-24 10:34
閱讀 3336·2021-11-22 13:53
閱讀 2639·2021-11-22 12:03
閱讀 3607·2021-09-26 09:47
閱讀 3014·2021-09-23 11:21
閱讀 4814·2021-09-22 15:08
閱讀 3302·2021-07-23 10:59
閱讀 1269·2019-08-29 18:31