你寫(xiě)的代碼能抗住雙11的流量嗎?
臨近雙十一,從 2009 年第一屆雙十一開(kāi)始,成交量只有 5000 萬(wàn),到去年 2019 年,成交量達(dá)到了 2684 億。今年迎來(lái)了第十二屆雙十一,想想都挺激動(dòng)。
阿里人喜歡將雙十一視為 Team Building(團(tuán)隊(duì)建設(shè)),廣為流傳的一句話:打仗是最好的團(tuán)建,沒(méi)有參加過(guò)雙十一的叫同事,參加過(guò)雙十一的叫戰(zhàn)友。
上一篇我通過(guò)三國(guó)故事講解了服務(wù)雪崩和熔斷的機(jī)制,而且自己造了一個(gè)輪子:熔斷器。而這一篇會(huì)講解被一線大廠使用的兩款流量防控組件:Sentinel 和 Hystrix,以及對(duì)它們的橫向?qū)Ρ?,以及?/span>如何選型。
本篇主要內(nèi)容如下:

本文已收錄到我的?Github:?https://github.com/Jackson0714/PassJava-Learning
一、熔斷&降級(jí)&限流&隔離
面對(duì)高并發(fā)的流量,我們通常會(huì)使用四種方式(熔斷&降級(jí)&限流&隔離)來(lái)防止瞬時(shí)大流量對(duì)系統(tǒng)的沖擊。而今天要介紹的這兩款流量防衛(wèi)兵,是專門用在這方面的。下面我先給同學(xué)掃個(gè)小盲。
什么是熔斷 ?

關(guān)鍵字:斷路保護(hù)。比如 A 服務(wù)調(diào)用 B 服務(wù),由于網(wǎng)絡(luò)問(wèn)題或 B 服務(wù)宕機(jī)了或 B 服務(wù)的處理時(shí)間長(zhǎng),導(dǎo)致請(qǐng)求的時(shí)間超長(zhǎng),如果在一定時(shí)間內(nèi)多次出現(xiàn)這種情況,就可以直接將 B 斷路了(A 不再請(qǐng)求B)。而調(diào)用 B 服務(wù)的請(qǐng)求直接返回降級(jí)數(shù)據(jù),不必等待 B 服務(wù)的執(zhí)行。因此 B 服務(wù)的問(wèn)題,不會(huì)級(jí)聯(lián)影響到 A 服務(wù)。
什么是降級(jí) ?

關(guān)鍵字:返回降級(jí)數(shù)據(jù)。網(wǎng)站處于流量高峰期,服務(wù)器壓力劇增,根據(jù)當(dāng)前業(yè)務(wù)情況及流量,對(duì)一些服務(wù)和頁(yè)面進(jìn)行有策略的降級(jí)(停止服務(wù),所有的調(diào)用直接返回降級(jí)數(shù)據(jù))。以此緩解服務(wù)器資源的壓力,保證核心業(yè)務(wù)的正常運(yùn)行,保持了客戶和大部分客戶得到正確的響應(yīng)。降級(jí)數(shù)據(jù)可以簡(jiǎn)單理解為快速返回了一個(gè) false,前端頁(yè)面告訴用戶“服務(wù)器當(dāng)前正忙,請(qǐng)稍后再試。”
什么是限流?

限流場(chǎng)景圖@悟空聊架構(gòu) 對(duì)請(qǐng)求的流量進(jìn)行控制, 只
放行部分請(qǐng)求,使服務(wù)能夠承擔(dān)不超過(guò)自己能力的流量壓力。熔斷和降級(jí)的相同點(diǎn)?
熔斷和限流都是為了保證集群大部分服務(wù)的 可用性和可靠性。防止核心服務(wù)崩潰。給終端用戶的感受就是某個(gè)功能不可用。 熔斷和降級(jí)的不同點(diǎn)?
熔斷是被調(diào)用方出現(xiàn)了故障,主動(dòng)觸發(fā)的操作。 降級(jí)是基于全局考慮,停止某些正常服務(wù),釋放資源。 什么是隔離?
每個(gè)服務(wù)看作一個(gè)獨(dú)立運(yùn)行的系統(tǒng),即使某一個(gè)系統(tǒng)有問(wèn)題,也不會(huì)影響其他服務(wù)。
二、Hystrix
Hystrix 是什么
Hystrix:高可用性保障的一個(gè)框架。由 Netflix 出品(Netflix可以理解為國(guó)內(nèi)的愛(ài)奇藝等視頻網(wǎng)站)。
Hystrix 的歷史
2011 年,其中的 API 團(tuán)隊(duì)為了提升系統(tǒng)的可用性和穩(wěn)定性,發(fā)展出了 Hystrix 框架。
2012 年,Hystrix 區(qū)域比較成熟穩(wěn)定。其他團(tuán)隊(duì)也開(kāi)始使用 Hystrix。
2018 年 11 月,Hystrix在其 Github 主頁(yè)宣布,不再開(kāi)放新功能,推薦開(kāi)發(fā)者使用其他仍然活躍的開(kāi)源項(xiàng)目。但是 Hystrix 價(jià)值依舊很大,功能強(qiáng)大,國(guó)內(nèi)很多一線互聯(lián)網(wǎng)公司在使用。
Hystrix 設(shè)計(jì)理念
阻止服務(wù)的雪崩效應(yīng)。 快速失敗和快速恢復(fù)。 優(yōu)雅降級(jí)。 使用資源隔離技術(shù),如 bulkhead(艙壁隔離技術(shù))、swimlane(泳道技術(shù))、circuit breaker(斷路技術(shù))。 近實(shí)時(shí)的監(jiān)控、報(bào)警及運(yùn)維操作。
Hystrix 線程池隔離技術(shù)
使用線程池隔離,比如說(shuō)有 3 個(gè)服務(wù) A、B、C,每個(gè)服務(wù)的線程池分配 10,20,30個(gè)線程,當(dāng) A 服務(wù)線程池中的 10 個(gè)線程都拿出來(lái)使用后,如果調(diào)用服務(wù) A 的請(qǐng)求量增加,還想再增加線程是不行的,因?yàn)?A 服務(wù)分配的線程已經(jīng)用完了,不會(huì)拿其他的服務(wù)的線程,這樣就不會(huì)影響其他服務(wù)了。Hystrix 默認(rèn)使用線程池隔離模式。

線程池隔離技術(shù)優(yōu)點(diǎn)
依賴的服務(wù)都有隔離的線程池,即使自己的線程池滿了,也不會(huì)影響任何其他其他的服務(wù)調(diào)用。 線程池的健康狀態(tài)會(huì)上報(bào),可以近實(shí)時(shí)修改依賴服務(wù)的調(diào)用配置。 線程池具有異步特性,可以構(gòu)建一層異步調(diào)用層。 具有超時(shí)檢測(cè)的機(jī)制,尤其在服務(wù)間調(diào)用特別有用。
線程池隔離技術(shù)缺點(diǎn)
線程池本身就會(huì)帶來(lái)一些問(wèn)題,比如線程切換,線程管理,無(wú)疑增加了 CPU 的開(kāi)銷。 如果線程池中的線程利用率很低,則無(wú)疑是一種浪費(fèi)。
Hystrix 信號(hào)量隔離技術(shù)
如下圖所示:簡(jiǎn)單來(lái)說(shuō)就是一個(gè)池子里面放著一定數(shù)量的信號(hào)量,服務(wù) A 每次調(diào)用服務(wù) B 之前,需要從池子里面申請(qǐng)信號(hào)量,申請(qǐng)到了,才能去調(diào)用 B 服務(wù)。

線程池隔離和信號(hào)量的場(chǎng)景對(duì)比
線程池隔離技術(shù) ,適合大部分場(chǎng)景,但需要設(shè)置服務(wù)的超時(shí)時(shí)間。 信號(hào)量隔離技術(shù) ,適合內(nèi)部比較復(fù)雜的業(yè)務(wù),不涉及網(wǎng)絡(luò)請(qǐng)求問(wèn)題。
三、Sentinel
3.1、Sentinel 是什么
Sentinel:面向分布式服務(wù)架構(gòu)的流量控制組件,主要以流量為切入點(diǎn),從限流、流量整形、熔斷降級(jí)、系統(tǒng)負(fù)載保護(hù)、熱點(diǎn)防護(hù)等多個(gè)維度來(lái)幫助開(kāi)發(fā)者保障微服務(wù)的穩(wěn)定性。
3.2、Sentinel 的歷史
2012 年,Sentinel 誕生,主要功能為入口流量控制。 2013-2017 年,Sentinel 在阿里巴巴集團(tuán)內(nèi)部迅速發(fā)展,成為基礎(chǔ)技術(shù)模塊,覆蓋了所有的核心場(chǎng)景。Sentinel 也因此積累了大量的流量歸整場(chǎng)景以及生產(chǎn)實(shí)踐。 2018 年,Sentinel 開(kāi)源,并持續(xù)演進(jìn)。 2019 年,Sentinel 朝著多語(yǔ)言擴(kuò)展的方向不斷探索,推出 C++ 原生版本,同時(shí)針對(duì) Service Mesh 場(chǎng)景也推出了 Envoy 集群流量控制支持,以解決 Service Mesh 架構(gòu)下多語(yǔ)言限流的問(wèn)題。 2020 年,推出 Sentinel Go 版本,繼續(xù)朝著云原生方向演進(jìn)。
3.3、Sentinel 的特征
豐富的應(yīng)用場(chǎng)景。 支撐阿里的雙十一核心場(chǎng)景,如秒殺、消息削峰填谷、集群流量控制、實(shí)時(shí)熔斷下游不可用。 完備的實(shí)時(shí)監(jiān)控。 可以看到接入應(yīng)用的單臺(tái)機(jī)器秒級(jí)數(shù)據(jù),以及集群的匯總情況。 廣泛的開(kāi)源生態(tài)。 Spring Cloud、Dubbo、gRPC 都可以接入 Sentinel。 完善的 SPI 擴(kuò)展點(diǎn)。 實(shí)現(xiàn)擴(kuò)展接口來(lái)快速定制邏輯。
用一張圖來(lái)總結(jié):

3.4、Sentinel 的組成
核心庫(kù)(Java 客戶端)不依賴任何框架/庫(kù),能在所有的 Java 運(yùn)行時(shí)環(huán)境運(yùn)行,且對(duì) Spring Cloud、Dubbo 等框架有較好的支持。 控制臺(tái)(Dashboard)基于 Spring Boot 開(kāi)發(fā),打包后可以直接運(yùn)行,不需要額外的 Tomcat 等應(yīng)用容器。
3.5、Sentinel 的資源
Sentinel 中的資源是核心概念,可以是 Java 應(yīng)用程序中的任何內(nèi)容,可以是提供的服務(wù),甚至是一段代碼。
可以通過(guò) Sentinel API 定義的代碼,就是資源,能夠被 Sentinel保護(hù)起來(lái)。可以如下幾種方式來(lái)標(biāo)識(shí)資源:
方法簽名。 URL。 服務(wù)名稱等。
3.6、Sentinel 的設(shè)計(jì)理念
Sentinel 作為一個(gè)流量控制器,可以根據(jù)需要把隨機(jī)的請(qǐng)求調(diào)整成合適的形狀,如下圖所示:

四、對(duì)比
4.1、隔離設(shè)計(jì)上對(duì)比
Hystrix
Hystrix 提供兩種隔離策略,線程池隔離和信號(hào)量隔離。
Hystrix 中最推薦的也是最常用的是線程池隔離。線程池隔離的好處是隔離度很高,不會(huì)影響其他資源,但是線程本身也有自己的問(wèn)題,線程上下文切換時(shí)比較耗 CPU 資源的,如果對(duì)低延時(shí)要求比較高,影響還是挺大的,而且創(chuàng)建線程是需要分配內(nèi)存的,創(chuàng)建的線程越多,需要分配的內(nèi)存也會(huì)更多。而且如果對(duì)每個(gè)資源都創(chuàng)建一個(gè)線程池,那線程切換會(huì)帶來(lái)更大的損耗。
而 Hystrix 的信號(hào)量隔離,可以對(duì)某個(gè)資源調(diào)用的并發(fā)數(shù)進(jìn)行限制,輕量級(jí)的,不用顯式創(chuàng)建線程池,但缺點(diǎn)是不能對(duì)慢調(diào)用進(jìn)行自動(dòng)降級(jí),只能等客戶端那邊超時(shí),還是有可能出現(xiàn)級(jí)聯(lián)阻塞的情形。
Sentinel
Sentinel 可以通過(guò)并發(fā)線程數(shù)模式的流量控制來(lái)提供信號(hào)量隔離的功能,而且它還具備響應(yīng)時(shí)間的熔斷降級(jí)模式,防止過(guò)多的慢調(diào)用占滿并發(fā)數(shù)而影響整個(gè)系統(tǒng)。
4.2、熔斷降級(jí)的對(duì)比
Sentinel 和 Hystrix 都是基于熔斷器模式。都支持基于異常比率來(lái)進(jìn)行熔斷,但 Sentinel 更強(qiáng)大,可以基于響應(yīng)時(shí)間、異常比率和異常數(shù)來(lái)進(jìn)行熔斷降級(jí)。
4.3、實(shí)時(shí)統(tǒng)計(jì)的對(duì)比
Sentinel 和 Hystrix 都是基于滑動(dòng)窗口進(jìn)行實(shí)時(shí)統(tǒng)計(jì),但 Hystrix 是基于 RxJava 的事件驅(qū)動(dòng)模型,在服務(wù)調(diào)用成功/失敗/超時(shí)的時(shí)候發(fā)布響應(yīng)的事件,通過(guò)一系列的變換和聚合最終得到實(shí)時(shí)的指標(biāo)統(tǒng)計(jì)數(shù)據(jù)流,可以被熔斷器或 Dashboard 消費(fèi)。而 Sentinel 是基于 LeapArray 的滑動(dòng)窗口。
五、Sentinel 的突出特性
除了上面提到的 三大對(duì)比外,Sentinel 還有一些 Hystrix 不具備的功能。
5.1、流量控制
流量控制: 其原理是監(jiān)控應(yīng)用流量的 QPS 或并發(fā)線程數(shù)等指標(biāo),當(dāng)達(dá)到指定的閾值時(shí)對(duì)流量進(jìn)行控制,以避免被瞬時(shí)的流量高峰沖垮,從而保障應(yīng)用的高可用性。
Sentinel 可以基于QPS/并發(fā)數(shù)進(jìn)行流量控制,也可以基于調(diào)用關(guān)系進(jìn)行流量控制。
基于 QPS 進(jìn)行流量控制有以下幾種方式:
直接拒絕: 當(dāng)QPS 超過(guò)一定閾值時(shí),直接拒絕。適用于對(duì)系統(tǒng)處理能力確切已知的情況。 慢啟動(dòng)預(yù)熱: 當(dāng)系統(tǒng)長(zhǎng)期處于低水位的情況下,當(dāng)流量突然增加時(shí),直接把系統(tǒng)拉升到高水位可能瞬間把系統(tǒng)壓垮。通過(guò)"冷啟動(dòng)",讓通過(guò)的流量緩慢增加,在一定時(shí)間內(nèi)逐漸增加到閾值上限,給冷系統(tǒng)一個(gè)預(yù)熱的時(shí)間,避免冷系統(tǒng)被壓垮。

勻速排隊(duì): 請(qǐng)求以均勻的速度通過(guò),對(duì)應(yīng)的是漏桶算法。

基于調(diào)用關(guān)系的流量控制:
根據(jù)調(diào)用方限流。 根據(jù)調(diào)用鏈路入口限流:鏈路限流。 根據(jù)具有關(guān)系的資源流量限流:關(guān)聯(lián)流量限流。
5.2、系統(tǒng)自適應(yīng)限流
Sentinel 系統(tǒng)自適應(yīng)限流從整體維度對(duì)應(yīng)用入口流量進(jìn)行控制,借助 TCP BBR 思想,結(jié)合應(yīng)用的 Load、CPU 使用率、總體平均 RT、入口 QPS 和并發(fā)線程數(shù)等幾個(gè)維度的監(jiān)控指標(biāo),通過(guò)自適應(yīng)的流控策略,讓系統(tǒng)的入口流量和系統(tǒng)的負(fù)載達(dá)到一個(gè)平衡,讓系統(tǒng)盡可能跑在最大吞吐量的同時(shí)保證系統(tǒng)整體的穩(wěn)定性。

我們把系統(tǒng)處理請(qǐng)求的過(guò)程想象為一個(gè)水管,到來(lái)的請(qǐng)求是往這個(gè)水管灌水,當(dāng)系統(tǒng)處理順暢的時(shí)候,請(qǐng)求不需要排隊(duì),直接從水管中穿過(guò),這個(gè)請(qǐng)求的RT是最短的;反之,當(dāng)請(qǐng)求堆積的時(shí)候,那么處理請(qǐng)求的時(shí)間則會(huì)變?yōu)椋号抨?duì)時(shí)間 + 最短處理時(shí)間。
推論一: 如果我們能夠保證水管里的水量,能夠讓水順暢的流動(dòng),則不會(huì)增加排隊(duì)的請(qǐng)求;也就是說(shuō),這個(gè)時(shí)候的系統(tǒng)負(fù)載不會(huì)進(jìn)一步惡化。
推論二:?當(dāng)保持入口的流量是水管出來(lái)的流量的最大的值的時(shí)候,可以最大利用水管的處理能力。
5.3、 實(shí)時(shí)監(jiān)控和控制面板
Sentinel 提供一個(gè)輕量級(jí)的開(kāi)源控制臺(tái),它提供機(jī)器發(fā)現(xiàn)以及健康情況管理、監(jiān)控(單機(jī)和集群),規(guī)則管理和推送的功能。

5.4、 發(fā)展及生態(tài)
Sentinel 針對(duì) Spring Cloud、Dubbo、gRPC 都進(jìn)行了適配,引入依賴和簡(jiǎn)單的配置即可快速接入 Sentinel,相信 Sentinel 將是未來(lái)流量防控的一大利器。我比較看好 Sentinel。
5.5、 Sentinel 和 Hystrix 對(duì)比總結(jié)

寫(xiě)在最后
有讀者問(wèn)我秒殺系統(tǒng)該怎么設(shè)計(jì),在之前的文章中,我已經(jīng)揭秘了秒殺系統(tǒng)的架構(gòu)設(shè)計(jì),下面我還是總結(jié)下秒殺系統(tǒng)關(guān)注的八大點(diǎn):

服務(wù)單一職責(zé)、獨(dú)立部署 庫(kù)存預(yù)熱、快速扣減 秒殺鏈接加密 動(dòng)靜分離 惡意請(qǐng)求攔截 流量錯(cuò)峰 限流&熔斷&降級(jí) 隊(duì)列削峰
