在今天暗赶,基于SOA的架構(gòu)已經(jīng)大行其道鄙币。伴隨著架構(gòu)的SOA化,相關(guān)聯(lián)的服務(wù)熔斷蹂随、降級十嘿、限流等思想,也在各種技術(shù)講座中頻繁出現(xiàn)岳锁。本文將結(jié)合Netflix開源的Hystrix框架绩衷,對這些思想做一個(gè)梳理。
背景
伴隨著業(yè)務(wù)復(fù)雜性的提高激率,系統(tǒng)的不斷拆分咳燕,一個(gè)面向用戶端的API,其內(nèi)部的RPC調(diào)用層層嵌套乒躺,調(diào)用鏈條可能會非常長招盲。這會造成以下幾個(gè)問題:
API接口可用性降低
引用Hystrix官方的一個(gè)例子,假設(shè)tomcat對外提供的一個(gè)application聪蘸,其內(nèi)部依賴了30個(gè)服務(wù),每個(gè)服務(wù)的可用性都很高表制,為99.99%健爬。那整個(gè)applicatiion的可用性就是:99.99%的30次方 = 99.7%,即0.3%的失敗率么介。
這也就意味著娜遵,每1億個(gè)請求,有30萬個(gè)失斎蓝獭设拟;按時(shí)間來算,就是每個(gè)月的故障時(shí)間超過2小時(shí)久脯。
系統(tǒng)被block
假設(shè)一個(gè)請求的調(diào)用鏈上面有10個(gè)服務(wù)纳胧,只要這10個(gè)服務(wù)中有1個(gè)超時(shí),就會導(dǎo)致這個(gè)請求超時(shí)帘撰。
更嚴(yán)重的跑慕,如果該請求的并發(fā)數(shù)很高,所有該請求在短時(shí)間內(nèi)都被block(等待超時(shí))摧找,tomcat的所有線程都block在此請求上核行,導(dǎo)致其他請求沒辦法及時(shí)響應(yīng)。
服務(wù)熔斷
為了解決上述問題蹬耘,服務(wù)熔斷的思想被提出來芝雪。類似現(xiàn)實(shí)世界中的“保險(xiǎn)絲“,當(dāng)某個(gè)異常條件被觸發(fā)综苔,直接熔斷整個(gè)服務(wù)惩系,而不是一直等到此服務(wù)超時(shí)位岔。
熔斷的觸發(fā)條件可以依據(jù)不同的場景有所不同,比如統(tǒng)計(jì)一個(gè)時(shí)間窗口內(nèi)失敗的調(diào)用次數(shù)蛆挫。
實(shí)現(xiàn)原理
實(shí)現(xiàn)原理講起來很簡單赃承,其實(shí)就是不讓客戶端“裸調(diào)“服務(wù)器的rpc接口,而是在客戶端包裝一層悴侵。就在這個(gè)包裝層里面瞧剖,實(shí)現(xiàn)熔斷邏輯。
拿Hystrix的helloword舉例:
public class CommandHelloWorld extends HystrixCommand<String> {
private final String name;
public CommandHelloWorld(String name) {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.name = name;
}
@Override
protected String run() {
//關(guān)鍵點(diǎn):把一個(gè)RPC調(diào)用可免,封裝在一個(gè)HystrixCommand里面
return "Hello " + name + "!";
}
}
//客戶端調(diào)用:以前是直接調(diào)用遠(yuǎn)端RPC接口抓于,現(xiàn)在是把RPC接口封裝到HystrixCommand里面,它內(nèi)部完成熔斷邏輯
String s = new CommandHelloWorld("World").execute();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
隔離策略: 線程 vs 信號量
缺省的浇借,上面的HystrixCommand是被扔到一個(gè)線程中執(zhí)行的捉撮,也就是說,缺省是線程隔離策略妇垢。
還有一種策略就是不搞線程池巾遭,直接在調(diào)用者線程中執(zhí)行,也就是信號量的隔離策略闯估。
關(guān)于這2者的詳細(xì)區(qū)別灼舍,可以去參見官網(wǎng)。
熔斷的參數(shù)配置
Hystrix提供了如下的幾個(gè)關(guān)鍵參數(shù)涨薪,來對一個(gè)熔斷器進(jìn)行配置:
circuitBreaker.requestVolumeThreshold //滑動窗口的大小骑素,默認(rèn)為20
circuitBreaker.sleepWindowInMilliseconds //過多長時(shí)間,熔斷器再次檢測是否開啟刚夺,默認(rèn)為5000献丑,即5s鐘
circuitBreaker.errorThresholdPercentage //錯(cuò)誤率,默認(rèn)50%
3個(gè)參數(shù)放在一起侠姑,所表達(dá)的意思就是:
每當(dāng)20個(gè)請求中创橄,有50%失敗時(shí),熔斷器就會打開莽红,此時(shí)再調(diào)用此服務(wù)筐摘,將會直接返回失敗,不再調(diào)遠(yuǎn)程服務(wù)船老。直到5s鐘之后咖熟,重新檢測該觸發(fā)條件,判斷是否把熔斷器關(guān)閉柳畔,或者繼續(xù)打開馍管。
服務(wù)降級
有了熔斷,就得有降級薪韩。所謂降級确沸,就是當(dāng)某個(gè)服務(wù)熔斷之后捌锭,服務(wù)器將不再被調(diào)用,此時(shí)客戶端可以自己準(zhǔn)備一個(gè)本地的fallback回調(diào)罗捎,返回一個(gè)缺省值观谦。
這樣做,雖然服務(wù)水平下降桨菜,但好歹可用豁状,比直接掛掉要強(qiáng),當(dāng)然這也要看適合的業(yè)務(wù)場景倒得。
關(guān)于Hystrix中fallback的使用泻红,此處不詳述,參見官網(wǎng)霞掺。
服務(wù)限流
限流在日常生活中也很常見谊路,比如節(jié)假日你去一個(gè)旅游景點(diǎn),為了不把景點(diǎn)撐爆菩彬,管理部門通常會在外面設(shè)置攔截缠劝,限制景點(diǎn)的進(jìn)入人數(shù)(等有人出來之后,再放新的人進(jìn)去)骗灶。
對應(yīng)到計(jì)算機(jī)中惨恭,比如要搞活動,秒殺等矿卑,通常都會限流喉恋。
說到限流沃饶,有個(gè)關(guān)鍵問題就是:你根據(jù)什么策略進(jìn)行限制母廷??
比如在Hystrix中糊肤,如果是線程隔離琴昆,可以通過線程數(shù) + 隊(duì)列大小限制;如果是信號量隔離馆揉,可以設(shè)置最大并發(fā)請求數(shù)业舍。
另外一個(gè)常見的策略就是根據(jù)QPS限制,比如我知道我調(diào)用的一個(gè)db服務(wù)升酣,qps是3000舷暮,那如果不限制,超過3000噩茄,db就可能被打爆下面。這個(gè)時(shí)候,我可用在服務(wù)端做這個(gè)限流邏輯绩聘,也可以在客戶端做沥割。
現(xiàn)在一般成熟的RPC框架耗啦,都有參數(shù)直接設(shè)置這個(gè)。
還有一些場景下机杜,可用限制總數(shù):比如連接數(shù)帜讲,業(yè)務(wù)層面限制“庫存“總量等等。椒拗。
限流的技術(shù)原理 -令牌桶算法
關(guān)于限流的原理似将,相信很多人都聽說過令牌桶算法,Guava的RateLimiter也已經(jīng)有成熟做法陡叠,這個(gè)自己去搜索之玩郊。
此處想強(qiáng)調(diào)的是,令牌桶算法針對的是限制“速率“枉阵。至于其他限制策略译红,比如限制總數(shù),限制某個(gè)業(yè)務(wù)量的count值兴溜,則要具體業(yè)務(wù)場景具體分析侦厚。
異步RPC
異步RPC主要目的是提高并發(fā),比如你的接口拙徽,內(nèi)部調(diào)用了3個(gè)服務(wù)刨沦,時(shí)間分別為T1, T2, T3。如果是順序調(diào)用膘怕,則總時(shí)間是T1 + T2 + T3想诅;如果并發(fā)調(diào)用,總時(shí)間是Max(T1,T2,T3)岛心。
當(dāng)然来破,這里有1個(gè)前提條件,這3個(gè)調(diào)用直接忘古,互相不依賴徘禁。
同樣,一般成熟的RPC框架髓堪,本身都提高了異步化接口送朱,F(xiàn)uture或者Callback形式。
同樣干旁,Hystrix也提高了同步調(diào)用驶沼、異步調(diào)用方式,此處不再詳述争群。
總結(jié)
服務(wù)限流回怜、熔斷、降級祭阀、異步RPC是基于SOA的分布式系統(tǒng)中一些常見的基本策略鹉戚,并且這些策略現(xiàn)在都有成熟的開源框架支持鲜戒。用好這些策略,對整個(gè)系統(tǒng)的容錯(cuò)性抹凳、穩(wěn)定性有很大幫助遏餐。