Hystrix 資源隔離概念講解與實(shí)操
1. 前言
在本節(jié)中,我將為各位同學(xué)介紹 Hystrix 的最后一個(gè)特性,那就是服務(wù)資源隔離。雖然服務(wù)資源隔離是 Hystrix 的最后一個(gè)特性,但是其在 Hystrix 中占著舉足輕重的地位,同時(shí),也是治理微服務(wù)項(xiàng)目的重要舉措,所以各位一定要學(xué)好本節(jié)內(nèi)容。
本節(jié)主要內(nèi)容:
-
服務(wù)資源隔離概念介紹;
-
Hystrix 實(shí)現(xiàn)服務(wù)資源隔離。
2. 什么是服務(wù)資源隔離
在我們正式介紹什么是服務(wù)資源隔離之前,我們先來(lái)了解一些前置的概念,這些概念是理解服務(wù)資源隔離的前提。
進(jìn)程與線程
進(jìn)程:進(jìn)程(Process)是計(jì)算機(jī)中的程序關(guān)于某數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),是系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位,是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ)。在當(dāng)代面向線程設(shè)計(jì)的計(jì)算機(jī)結(jié)構(gòu)中,進(jìn)程是線程的容器。
我們可以把進(jìn)程理解為我們項(xiàng)目運(yùn)行的載體,就比如我們乘坐的公交車,公交車相對(duì)于我們來(lái)說(shuō)就是一個(gè)載體,來(lái)承載我們到達(dá)不同的目的地,進(jìn)程就是如此,只不過(guò)在進(jìn)程中被承載的是線程罷了。
線程:線程(Thread)是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位。我們可以把線程理解為,執(zhí)行某一具體的計(jì)算機(jī)系統(tǒng)任務(wù)的執(zhí)行者,比如在公交車中,負(fù)責(zé)開(kāi)公交車的司機(jī)師傅就可以被當(dāng)做一個(gè)線程。
在一個(gè)進(jìn)程中,可以存在多個(gè)線程,即在一輛公交車中可以存在多名乘客,他們分別都去往不同的目的地,但是,一個(gè)線程只能屬于一個(gè)進(jìn)程,不屬于不同的兩個(gè)進(jìn)程,即一名乘客同一時(shí)刻只能乘坐一輛公交車,不可能在同一時(shí)刻乘坐兩輛公交車。
在理解了什么是進(jìn)程與線程之后,我們來(lái)看一下在我們的 Web 項(xiàng)目中,進(jìn)程與線程都是怎樣存在的,以及他們之間的關(guān)系是怎樣的。
Web 項(xiàng)目中的進(jìn)程與線程
我們的每一個(gè) Web 項(xiàng)目都可以被看作一個(gè)進(jìn)程,且一個(gè) Web 項(xiàng)目只能是一個(gè)進(jìn)程。在我們的 Web 項(xiàng)目中,常規(guī)情況下只有兩個(gè)線程,分別是主線程和工作線程,其中,主線程負(fù)責(zé)我們的項(xiàng)目啟動(dòng)以及一些項(xiàng)目初始化工作,而工作線程則主要負(fù)責(zé)項(xiàng)目中的請(qǐng)求處理與業(yè)務(wù)邏輯執(zhí)行,項(xiàng)目中進(jìn)程與線程的關(guān)系如下圖所示:

根據(jù)上圖,我們可以這樣理解:一個(gè) Web 項(xiàng)目在計(jì)算機(jī)系統(tǒng)中就是一個(gè)進(jìn)程,而在這個(gè)進(jìn)程中,存在一個(gè)主線程和一個(gè)工作線程,并且主線程主要負(fù)責(zé)項(xiàng)目啟動(dòng),而工作線程主要負(fù)責(zé)請(qǐng)求的處理。
在理解了這個(gè)關(guān)系之后,讓我們來(lái)看一下什么是服務(wù)資源隔離。
服務(wù)資源隔離
在介紹服務(wù)資源隔離之前,我們需要先了解什么是服務(wù)資源。
服務(wù)資源一般來(lái)講,指的是項(xiàng)目正常運(yùn)行所需要的基礎(chǔ)環(huán)境、基礎(chǔ)設(shè)施、靜態(tài)資源文件等內(nèi)容,而對(duì)于 Web 項(xiàng)目來(lái)說(shuō),其項(xiàng)目本身即是一種服務(wù)資源,服務(wù)調(diào)用者通過(guò)調(diào)用項(xiàng)目提供的服務(wù)來(lái)滿足他們的業(yè)務(wù)需求。
而對(duì)于服務(wù)提供者來(lái)說(shuō),這些業(yè)務(wù)需求的實(shí)現(xiàn)在項(xiàng)目中一般就是我們所開(kāi)發(fā)的接口,所以,在項(xiàng)目中所實(shí)現(xiàn)的業(yè)務(wù)接口即是我們這里所說(shuō)的服務(wù)資源。
那么,為什么需要把服務(wù)資源進(jìn)行隔離呢?
我們知道,正常情況下,在 Web 項(xiàng)目中只有一個(gè)工作線程,且這個(gè)工作線程負(fù)責(zé)接口請(qǐng)求的處理。在正常應(yīng)用場(chǎng)景下,服務(wù)調(diào)用者會(huì)調(diào)用我們項(xiàng)目所提供的接口來(lái)滿足業(yè)務(wù)需求,這里假設(shè)我們的一個(gè) Web 項(xiàng)目中具有 5 個(gè)接口,服務(wù)調(diào)用者會(huì)根據(jù)業(yè)務(wù)順序來(lái)調(diào)用我們的接口,如果一切順利,則業(yè)務(wù)即可正常順利地進(jìn)行下去。
但是,如果服務(wù)調(diào)用者在調(diào)用接口時(shí),其中一個(gè)接口所需要處理的業(yè)務(wù)比較復(fù)雜,導(dǎo)致這個(gè)接口不能及時(shí)的結(jié)束,這就導(dǎo)致我們后續(xù)的接口調(diào)用只能等待,直到該接口處理完畢后才能繼續(xù)向下執(zhí)行,如果該接口一直不能處理完畢,則后續(xù)接口就會(huì)一直等待,從而影響業(yè)務(wù)的正常開(kāi)展,這種現(xiàn)象就被稱為服務(wù)資源等待,如下圖所示:

我們可以把上圖中的工作線程訪問(wèn)理解為服務(wù)調(diào)用者,在服務(wù)調(diào)用者調(diào)用接口 2 時(shí),由于接口 2 遲遲不能處理,導(dǎo)致接口 2 出現(xiàn)服務(wù)等待,并最終影響后續(xù)的接口 3、接口 4、接口 5 的調(diào)用,從而影響了業(yè)務(wù)的順利進(jìn)行。
如果通過(guò)采取某種措施,使?jié)M足同一業(yè)務(wù)需求的不同服務(wù)資源間進(jìn)行隔離,來(lái)有效緩解或解決服務(wù)資源等待問(wèn)題,那么業(yè)務(wù)就可以正常順利地開(kāi)展下去,所以人們就提出了服務(wù)資源隔離的概念。
3. Hystrix 實(shí)現(xiàn)服務(wù)資源隔離
在 Hystrix 中,實(shí)現(xiàn)服務(wù)資源隔離有兩種方式,分別是線程池隔離和信號(hào)量隔離。
3.1 線程池隔離實(shí)現(xiàn)服務(wù)資源隔離
通過(guò)對(duì)處理項(xiàng)目中的工作線程的隔離,來(lái)避免工作線程處理接口時(shí)所產(chǎn)生的阻塞行為,從而保證工作線程可以順利地調(diào)用接口來(lái)滿足業(yè)務(wù)需要。
而隔離工作線程的方式,就是為每個(gè)接口分配一個(gè)線程池,并在線程池中維護(hù)一定數(shù)量的線程,這樣,當(dāng)上述的接口 2 發(fā)生服務(wù)資源等待時(shí),由于每個(gè)接口都分配了不同的線程池,所以不會(huì)影響到后續(xù)的 3 4 5 接口,如下圖所示:

可以看到,由于為每個(gè)服務(wù)接口均分配了不同的線程池,所以在接口 2 出現(xiàn)服務(wù)等待時(shí),并不會(huì)影響后續(xù)接口的調(diào)用,從而保證了業(yè)務(wù)的順利進(jìn)行。
我們繼續(xù)以 hello 方法為例,來(lái)看如何實(shí)現(xiàn)線程池隔離。
@RequestMapping(value = "hello", method = RequestMethod.GET)
@HystrixCommand(threadPoolKey = "HelloHystrix", threadPoolProperties = {
@HystrixProperty(name = "coresize", value = "2"),
@HystrixProperty(name = "allowMaximumSizeToDivergeFromCoreSize", value = "true"),
@HystrixProperty(name = "maximumSize", value = "2"),
@HystrixProperty(name = "maxQueueSize", value = "2")
})
@ResponseBody
public String hello() throws InterruptedException {
return "helloWorld";
}
代碼解釋:
第 2 行,我們通過(guò)配置 HystrixCommand 注解的 threadPoolKey 屬性來(lái)為本接口分配一個(gè)名稱為 HelloHystrix 的線程池。
第 3 行,我們通過(guò)配置 threadPoolProperties 中的參數(shù)屬性,來(lái)維護(hù) HelloHystrix 線程池中的核心線程數(shù)量、最大線程數(shù)量。
通過(guò)添加上述注解并配置其中的屬性,我們就可以通過(guò)線程池隔離的方式來(lái)實(shí)現(xiàn)服務(wù)資源隔離。
Tips: 線程池中的線程數(shù)量,一定要根據(jù)該接口所實(shí)現(xiàn)的業(yè)務(wù)需求來(lái)設(shè)置,設(shè)置過(guò)多,則會(huì)浪費(fèi)資源空間,設(shè)置過(guò)少,則不能支撐業(yè)務(wù)需要,所以配置線程數(shù)量一定要謹(jǐn)慎。
3.2 信號(hào)量隔離實(shí)現(xiàn)服務(wù)資源隔離
信號(hào)量隔離和線程池隔離的方式很相似,只不過(guò)把分配線程池的方式改為了分配信號(hào)量(至于什么是信號(hào)量,請(qǐng)同學(xué)們自行查閱)。
在處理請(qǐng)求時(shí),Hystrix 會(huì)分配一個(gè)信號(hào)量的閥值,當(dāng)服務(wù)接收到一個(gè)請(qǐng)求后,信號(hào)量的閥值減 1 ,當(dāng)請(qǐng)求處理完畢后,信號(hào)量的閥值加 1,當(dāng)信號(hào)量的閥值減為 0 時(shí),則不再接收請(qǐng)求,即該請(qǐng)求會(huì)被拒絕處理。
@RequestMapping(value = "hello", method = RequestMethod.GET)
@HystrixCommand(fallbackMethod="helloFail", commandProperties = {
@HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY, value = "SEMAPHORE"),
@HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, value = "100")
})
@ResponseBody
public String hello() throws InterruptedException {
return "helloWorld";
}
public String helloFail() {
return "helloFailed";
}
代碼解釋:
第 4 行,通過(guò)指定 HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY
參數(shù)的值為 SEMAPHORE ,來(lái)聲明該接口使用信號(hào)量隔離。
第 7 行,通過(guò)指定 HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS
參數(shù)的值為 100 ,可以理解為設(shè)置信號(hào)量的閥值為 100 。
通過(guò)添加上述配置參數(shù),我們就可以通過(guò)信號(hào)量隔離的方式來(lái)實(shí)現(xiàn)服務(wù)資源隔離。
Tips: 一定要合理設(shè)置信號(hào)量的閥值,不要隨意設(shè)定,如果閥值設(shè)置過(guò)大,則請(qǐng)求不會(huì)停止,如果閥值設(shè)置過(guò)小,則不能滿足業(yè)務(wù)需要。
4. 視頻演示
5. 小結(jié)

本小節(jié)從服務(wù)資源隔離的前提概念開(kāi)始介紹,采用圖文并茂的方式,詳細(xì)介紹了進(jìn)程和線程、Web 項(xiàng)目中的進(jìn)程與線程、服務(wù)資源隔離產(chǎn)生的原因,以及服務(wù)資源隔離的概念;接著,我們采用代碼實(shí)現(xiàn)的方式,對(duì) Hystrix 中的線程池隔離和信號(hào)量隔離這兩種實(shí)現(xiàn)服務(wù)資源隔離的措施進(jìn)行了介紹,并對(duì)其中需要注意的地方做了補(bǔ)充。
服務(wù)資源隔離是微服務(wù)項(xiàng)目治理中的最后一關(guān),同時(shí)也是至關(guān)重要的一關(guān),微服務(wù)項(xiàng)目經(jīng)常由于服務(wù)沒(méi)有響應(yīng)而導(dǎo)致后續(xù)服務(wù)癱瘓,所以,掌握服務(wù)資源隔離是保證微服務(wù)項(xiàng)目正常運(yùn)行的關(guān)鍵所在。