開發

阿里巴巴開源限流降級神器Sentinel大規模生產級應用實踐

作者:丁浪,目前在創業公司擔任高級技術架構師。曾就職于阿里巴巴大文娛和螞蟻金服。具有豐富的穩定性保障,全鏈路性能優化的經驗。架構師社區特邀嘉賓!

前言

互聯網上關于限流算法、Sentinel功能介紹、基本結構、原理分析的文章可謂汗牛充棟,我并不打算重復制造內容。我將為大家分享在實際工作和生產環境中使用、踩坑的經驗。

如果你正在做限流、熔斷的技術選型,那么本文將會為你提供客觀、有價值的參考;

如果你將來要在生產環境中使用Sentinel,那么本文將會幫助你后續少走彎路;

如果你正在準備求職面試,或許可以幫你的技能樹和經驗上增加亮點,避免你的面試評價表上被人寫上“紙上談兵”;

開源版Sentinel和阿里內部的是一樣的嗎?我們可以在大規模生產級應用嗎?

這里我先直接告訴大家答案:開源的和內部版本是一樣的,最核心的代碼和能力都開源出來了。可以生產級應用,但并非 “開箱即用”,需要你做一些二次開發和調整,接下來我會對這些問題仔細展開。當然,我更推薦你直接使用阿里云上的AHASSentinel 控制臺和ASM配置中心,那是最佳實踐的輸出,你可以節省很多時間、人力、運維成本等。

總體運行架構

大規模生產級應用面臨的問題

看完Sentinel開源版原始的運行架構,很明顯其中存在一些問題:

1.    限流、降級等規則保存在應用節點的內存中,應用發布重啟后就會失效,這在生產環境中顯然是無法接受的;

2.    規則下發默認是按照機器節點維度的而非按應用維度,而正常公司的應用系統都是集群部署的,而且這樣也無法支持集群限流;

3.    metrics信息由Dashboard拉取上來后保存到內存中,僅僅保留5分鐘,錯過后可能無法還原 “案發現場”,而且無法看到流量趨勢;

4.    如果接入限流的應用有500+個,每個應用平均部署4個節點,那么總共2000個節點,那么Dashboard肯定會成為瓶頸,單機的線程池根本處理不過來;

如何優化并解決這些問題

接下來,我們就先一一的介紹如何解決上述這些明顯的問題。

首先,限流規則、降級規則等都應該按照應用維度去下發,而不是按照APP單節點的維度。因為Sentinel支持集群限流,所以開源版本的SentinelDashbord 在針對限流規則這塊已經做了擴展,但對于熔斷、系統保護等還未擴展支持按應用維度下發,感興趣的讀者可以參考FlowControllerV2的實現去實現。

其次,規則不應該保存內存中,應該持久化到動態配置中心,而應用直接從配置中心訂閱規則即可。這樣,Dashboard和應用就通過配置中心實現解耦了,這是典型的生產者消費者模式,基本運行架構如下:

以nacos配置中心為例,Sentinel官方和社區提供了限流規則保存和訂閱的Demo,接下來熔斷降級、系統保護、網關限流…等規則你其實都可以“照貓畫虎”的去擴展。基本模式就是:Dashboard將xxRuleEntityVO模型序列化后保存到nacos,應用從nacos訂閱后反序列成xxRule領域模型。

這里我特別提醒一下各位前方有巨坑,“熱點參數限流規則”和“黑名單限制規則”這塊請勿直接照搬,因為Dashboard 中定義的ParamFlowRuleEntity、AuthorityRuleEntity

這2個VO模型和領域模型ParamFlowRule、AuthorityRule中的字段定義不匹配,會導致序列化/反序列化失敗的問題,繼而導致應用無法訂閱和使用熱點參數限流規則和黑名單限制規則,這塊我會提交PR!!!

第3點,Dashboard中有個調度線程池,會輪詢方式請求(默認是每隔1秒鐘發起)各應用的機器節點查詢metrics日志信息,聚合后并在界面上做監控展示(改造后還需完成持久化動作)。這是典型的pull模式,是目前監控度量領域比較通用的架構。因為是保存內存中所以默認僅保留5分鐘,這也是有問題的。推薦有如下幾種解法:

1.    Dashboard在拉取到metrics信息后,直接保存到時序數據庫中,Dashboard自身也從時序數據庫中取數據展示。metrics數據存多久,這個你自己根據業務來決定。以開源的Influxdb為例其自帶持久策略功能(數據過期自動清理)。并且,你還可以借助Grafana等開源Dashboard做查詢、聚合,展示各種漂亮的大盤、圖形、排行榜等;

2.    你可以將pull的模式改為push模式,在記錄metrics日志時改為直接寫時序數據庫,當你,基于性能的考慮你也可以改為寫MQ做緩沖。除了耗時,最關鍵的是不能因為這個記錄metrics的動作影響到主業務流程的推進;

3.    繼續打印metrics日志,啟用SentinelDashboard拉取metrics數據,改用直接在應用機器節點上通過采集器對metrics日志做采集、處理、上報,可以借助ELK等工具;

4.    你可以嘗試自己開發PrometheusExporter,自己將metrics信息以Target形式暴露出去,由Prometheus服務端定時去拉取,同時你也可以使用Prometheus提供的各種豐富的查詢、聚合的語法和能力,通過Grafana等做展示;

下圖是典型的時序數據的例子,天生就是為metrics指標數據而設計的,該領域比較知名的開源軟件有OpenTSDB、Influxdb等。

Grafana限流大盤展示效果圖

以上方式各有優劣,如果你想改動最小,并且你們應用接入和部署規模并不是特別大(500節點以內),那么請選擇第1種方式。

第4點,關于接入應用和節點較多導致Dashboard在拉取、聚合時的性能瓶頸。在解決問題3的時候,如果你選擇了2,3,4這幾種方法,那么Sentinel自帶的Dashboard將僅僅作為規則下發的工具(甚至規則下發都可以直接通過nacos配置中心的控制臺完成),自然就不會有瓶頸的問題了。如果你依舊想借助Sentinel自帶的Dashboard來完成metrics數據的拉取和持久化等任務,那么我提供給你有兩個解法:

1.    按領域隔離,不同業務域的應用連接到各自的SentinelDashboard上,這樣自然就分攤壓力減少瓶頸出現的可能性了。優點就是幾乎無需做改造,缺點就是顯得不統一;

2.    你可以嘗試改造Sentinel自帶的Dashboard,讓其具備無狀態性。前面我們提過,應用端啟動后會定時上報心跳信息,Dashboard這邊默認會在內存中維護一份 “節點信息列表”的數據,這個是典型的狀態性數據,應該考慮放到集中存儲中,例如:redis中。然后你需要改造“拉取metrics信息”的線程池,改為分片任務方式去執行,這樣達到分攤負載的作用,例如:改為使用elasticjob調度。當然,時序數據庫的寫入也是有可能成為瓶頸的;

3.    你可以犧牲一點監控指標的時效性,將Sentinel Dashboard中fetchScheduleService調度線程池的間隔時間參數調大一點,這樣可以緩解下游工作線程池的處理壓力;

就我個人而言其實更推薦第1,3這兩種方式,這都是改動比較小的權宜之計。

當然,按領域劃分其實也是有其他好處的。你試想如果接入了500+系統,以目前開源版的Dashboard為例,左側應用列表得拉多長?估計沒法使用了,這UI和交互設計上都是業余的顯然無法滿足大規模生產級應用的。但是按領域隔離后,或許在體驗上會有所改善。而且還有一點,目前開源版本的Dashboard只提供了最基本的登錄驗證功能,如果你想要權限控制、審計、審批確認等功能是需要二次開發的。如果Dashboard這塊按領域獨立了,在權限控制這塊的風險性會更小。

當然,如果你想重構Dashboard權限控制以及UI交互這些,我建議是按照應用維度來設計,加入基本的搜索等。

其他的問題

應用在接入Sentinel后,需要啟動時指定應用名稱、Dashboard地址、客戶端的端口號、日志配置、心跳設置等,要么通過JVM -D啟動參數來實現,要么在指定的路徑下存放配置文件來配置。這都是不太合理的設計,對CI/CD和部署環境有侵入性,我在1.6.3版本時解決了這個問題并提交過PR,好在社區在1.7.0時解決了這個問題。

規則配置和使用上的一些經驗

請不要誤會,我不是教你怎么配置怎么使用,而是教你如何用好,還記得我在之前穩定性保障體系的文章中拋出關于限流的靈魂拷問嗎?首先,我們簡單回顧下可能會用到的Sentinel中的關鍵功能。接下來我將以自問自答的方式解答使用者最常見的疑惑,輸出最有價值的經驗和建議。

1.    單機限流

2.    集群限流

3.    網關限流

4.    熱點參數限流

5.    系統自適應保護

6.    黑白名單限制

7.    自動熔斷降級

單機限流閾值配多少?

這個不能“拍腦袋”,配太高了可能會引發故障,配太低了又擔心過早“誤殺”請求。還是得根據容量規劃和水位設定來配置,而且前提是監控告警靈敏。給出兩種比較實用的方式:

1.    參考單機容量規劃的思路,在軟負載中調整某個節點的流量權重和比例直到逼近極限為止。記錄極限狀態下的QPS,按照單機房70%的水位設定標準,你就可以推算出該資源的單機限流閾值了;

2.    你可以周期性觀察監控系統的流量圖,得到線上真實的峰值QPS,如果該周期內峰值時段應用系統和業務都是健康狀態的,那么你可以假設該峰值QPS就是理論水位。這種方式是可能造成資源浪費的,因為峰值時段可能并未達到系統承載極限,適合流量周期性比較規律的業務;

你真的需要集群限流嗎?

其實大多數場景下你并不需要使用集群限流,單機限流就足夠了。仔細思考其實只有幾種情況下可能需要使用到集群限流:

1.    當想要配置單機QPS限制 <1 時單機模式是無法滿足的,只能使用集群限流模式來限制集群的總QPS。比如有個性能極差的接口單機最多只能扛住0.5QPS,部署了10臺機器那么需要將集群最大容量是5 QPS,當然這個例子有點極端。再比如我們希望某個客戶調用某個接口總的最大QPS為10,但是實際我們部署了20臺機器,這種情況是真實存在的;

2.    上圖中單機限流閾值是10 QPS,部署了3個節點,理論上集群的總QPS可以達到30,但是實際上由于流量不均勻導致集群總QPS還沒有達到30就已經觸發限流了。很多人會說這不合理,但我認為需要按真實情況來分析。如果這個 “10QPS”是根據容量規劃的系統承載能力推算出來的閾值(或者說該接口請求如果超過10 QPS就可能會導致系統崩潰),那這個限流的結果就是讓人滿意的。如果這個“10QPS”只是業務層面的限制,即便某個節點的QPS超過10了也不會導致什么問題,其實我們本質上是想限制整個集群總的QPS,那么這個限流的結果就不是合理的,并沒有達到最佳效果;

所以,實際取決于你的限流是為了實現“過載保護”,還是實現業務層的限制。

還有一點需要說明的是:集群限流并無法解決流量不均勻的問題,限流組件并不能幫助你重新分配或者調度流量。集群限流只是能讓流量不均勻場景下整體限流的效果更好。

實際使用建議是:集群限流(實現業務層限制)+ 單機限流(系統兜底,防止被打爆)

既然網關層已經限流了,那應用層還需要限流嗎?

需要的,雙重保護是很有必要。同理,上游的聚合服務配置了限流,下游的基礎服務也是需要配置限流的,試想下如果只配置了上游的限流,如果上游發起大量重試豈不是依舊可能壓垮下游的基礎服務?而且這種情況,我們在配置限流閾值時也需要特別注意,比如上游的A,B兩個服務都依賴了下游Y服務,A,B分別配置的100QPS,那么Y服務至少得配置為200QPS,要不然有部分請求額外的經過透傳和處理但最終又被拒絕,不僅是浪費資源,嚴重了還可能導致數據不一致等問題。

所以,最好是根據全鏈路總體的容量規劃來配置(木桶短板原理),越早攔截越好,每一層都要配置限流。

熱點參數限流功能實用嗎?

功能挺實用的,可以防止熱點數據(比如:熱門店鋪、黑馬商品)占用并消耗過多的系統資源,導致對其他數據的請求處理受到嚴重影響。

還有一種需求,如果你做C端的產品,你想限制某用戶訪問某接口的最大QPS,或者你是做B端的SAAS產品,你想限制某租戶訪問某接口的最大QPS…熱點參數默認不是為了滿足這類需求而設計的,你需要自行擴展SLOT去實現類似的限制需求。當然,熱點參數限流中的paramFlowItemList(參數例外項,可以實現指定某個客戶ID=1的大客戶訪問某資源的最大QPS為100),這在某種程度上是可以實現這種特殊需求的。對于這種需求還有一種解決辦法:我們在代碼中定義resouceName時就直接給它賦予對應的業務數據標識(例如:queryAmount#{租戶Id}),然后根據resouceName去控制臺單獨配置。

為什么還整出個系統自適應保護啊?

這個其實也是一種兜底的做法。當真實流量超過限流閾值一部分時,開銷基本可以忽略,當真實流量遠超限流閾值N倍時,尤其是像雙十一大促、春晚紅包、12306購票這種巨大流量的場景下,那么限流拒絕請求的開銷就不能忽略了,這種情況在阿里內部稱為“系統被摸死”,這種場景下自適應限流可以做好兜底。

黑白名單限制需要配嗎?

如果你想根據請求來源做限制(僅放行指定上游系統過來的請求),那么該功能非常有用的。Sentinel中內置了“簇點鏈路監控”功能,有點類似調用鏈監控但目的不一樣。

自動熔斷降級有啥使用建議?

配置自動熔斷降級前,首先我們需要識別出可能出現不穩定的服務,然后判斷其是否可降級。降級處理通常是快速失敗,當然我們業可以自定義降級處理結果(Fallback),例如:嘗試包裝返回默認結果(兜底降級),返回上一次請求的緩存結果(時效性降級),包裝返回處理失敗的提示結果等。

對弱依賴和次要功能的降級通常是人工推送開關來完成的,而Sentinel的熔斷降級主要是在“調用端”自動判斷并執行的,Sentinel基于規則中配置的時間窗口內的平均響應時間、錯誤比例、錯誤數等統計指標來執行自動熔斷降級。

舉個例子:我們系統同時支持“余額支付”和“銀行卡支付”,這兩個功能對應的接口默認在相同應用的同一線程池中,任何一方出現RT抖動和大量超時都可能請求積壓并導致線程池被耗盡。假設從業務角度來看“余額支付”的比例更高,保障的優先級也更高。那么我們可以在檢查到 “銀行卡支付”接口(依賴第三方,不穩定)中RT持續上升或者發生大量異常時對其執行“自動熔斷降級”(前提是不能導致數據不一致等影響業務流程的問題),這樣優先保證“余額支付”的功能可以繼續正常使用。

總結

本文主要介紹了Sentinel開源版在大規模生產級應用時所面臨的一些問題和解法,還有在實際配置使用時的一些經驗,這些經驗均來自一線生產實踐,希望能讓讀者朋友少走彎路。

我還沒有學會寫個人說明!

面向客戶編程!為滿足新業務定位,谷歌云計算實施裁員計劃

上一篇

Kubernetes Ingress 控制器的技術選型技巧

下一篇

你也可能喜歡

阿里巴巴開源限流降級神器Sentinel大規模生產級應用實踐

長按儲存圖像,分享給朋友

ITPUB 每周精要將以郵件的形式發放至您的郵箱


微信掃一掃

微信掃一掃
重庆时时后一8码方法 秒秒彩开奖原理 福彩辽宁35选7开奖结果查询 排列7中奖规则查询 安徽快三直播视频下载 独行侠季前赛赛程 最好的理财产品 3d定胆技巧准确率98 北京28被骗经历 一本道种子图片 牛散石庭波手法 26选5开奖结果要多久出来 下载琼崖海南麻将 股票涨跌的机制 有一万块闲钱如何理财 七乐彩最新走势图 天津十一选五开奖号码 新闻