使用Sentinel滑動(dòng)窗口實(shí)現(xiàn)限流和降級(jí)
Sentinel滑動(dòng)窗口前言
Sentinel 是一個(gè)開(kāi)源的高可用性、高擴(kuò)展性的實(shí)時(shí)流量控制框架,它可以用于保護(hù)服務(wù)穩(wěn)定性,防止系統(tǒng)因?yàn)榱髁窟^(guò)大而崩潰。今天我們所介紹的,是滑動(dòng)窗口,它是 Sentinel 實(shí)現(xiàn)限流和降級(jí)的重要組件之一。
Sentinel滑動(dòng)窗口原理
滑動(dòng)窗口通常由一個(gè)固定大小的時(shí)間窗口和一個(gè)可滑動(dòng)的數(shù)據(jù)結(jié)構(gòu)組成,例如隊(duì)列或滑動(dòng)塊。在 Sentinel 中,滑動(dòng)窗口被分為計(jì)數(shù)器類(lèi)型和預(yù)算類(lèi)型:
計(jì)數(shù)器滑動(dòng)窗口:計(jì)數(shù)器滑動(dòng)窗口維護(hù)一個(gè)周期內(nèi)請(qǐng)求的總數(shù),當(dāng)周期結(jié)束后,滑動(dòng)窗口會(huì)被清空,開(kāi)始下一個(gè)周期的計(jì)數(shù)。在 Sentinel 中,計(jì)數(shù)器滑動(dòng)窗口通過(guò) AtomicLong 數(shù)組實(shí)現(xiàn),數(shù)組的長(zhǎng)度代表時(shí)間窗口的大小,每個(gè)元素代表該時(shí)間片保存的請(qǐng)求次數(shù)。
預(yù)算滑動(dòng)窗口:預(yù)算滑動(dòng)窗口維護(hù)周期內(nèi)預(yù)算資源的使用情況,以便根據(jù)實(shí)際資源需要進(jìn)行限流或降級(jí)。預(yù)算類(lèi)型的滑動(dòng)窗口可以設(shè)置閾值,并支持動(dòng)態(tài)調(diào)整。在 Sentinel 中,預(yù)算滑動(dòng)窗口通常用于 CPU 使用率、線(xiàn)程池等容量資源的控制。
除此之外,Sentinel 還提供了基于單機(jī)、集群和分布式三種模式的滑動(dòng)窗口實(shí)現(xiàn)。其中,單機(jī)模式下將使用本地內(nèi)存來(lái)維護(hù)滑動(dòng)窗口數(shù)據(jù)結(jié)構(gòu);集群模式下,各節(jié)點(diǎn)會(huì)通過(guò)多播或 Redis 等方式共享相同的計(jì)數(shù)器數(shù)據(jù);分布式模式下,則允許多個(gè)服務(wù)節(jié)點(diǎn)公用同一組滑動(dòng)窗口數(shù)據(jù)。
在使用 Sentinel 進(jìn)行限流和降級(jí)時(shí),用戶(hù)可以通過(guò)配置規(guī)則來(lái)指定需要監(jiān)控的目標(biāo)資源,并設(shè)置相應(yīng)的閾值和處理策略。例如,在限流場(chǎng)景下,用戶(hù)可以設(shè)置最大 QPS,并指定超過(guò)該閾值的請(qǐng)求將會(huì)被丟棄或返回特定的錯(cuò)誤碼。在降級(jí)場(chǎng)景下,用戶(hù)可以設(shè)置響應(yīng)時(shí)間、異常比例等閾值,并指定相應(yīng)的降級(jí)策略,例如返回默認(rèn)值或者直接拋出異常。
如何在項(xiàng)目中使用滑動(dòng)窗口
以實(shí)際的項(xiàng)目為例子,我們有一個(gè)服務(wù)用于提供用戶(hù)信息查詢(xún)接口,每秒鐘最多只能處理 10 次查詢(xún)請(qǐng)求,并且如果連續(xù) 5 秒內(nèi)的請(qǐng)求次數(shù)超過(guò) 50 次,則觸發(fā)限流或降級(jí)操作。
在 Sentinel 中,我們首先需要定義一個(gè) FlowRule 數(shù)組用于配置針對(duì)該服務(wù)的限流規(guī)則,在這塊項(xiàng)目例子中,它們是每秒鐘限流到 10 個(gè)請(qǐng)求和 5 秒內(nèi)超過(guò) 50 次請(qǐng)求兩種限制:
FlowRule rule1 = new FlowRule();
rule1.setResource("queryUser");
rule1.setCount(10);
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
FlowRule rule2 = new FlowRule();
rule2.setResource("queryUser");
rule2.setCount(50);
rule2.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule2.setStrategy(RuleConstant.STRATEGY_CHAIN);
rule2.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);我們先對(duì)以上代碼進(jìn)行解釋?zhuān)?ldquo;queryUser” 代表資源名稱(chēng),這個(gè)可以自己定義,然后設(shè)置了resource、count、grade以及對(duì)于第二個(gè)規(guī)則還增加了三個(gè)屬性stratety, controlBehavior和controlBehavior。其中 count 表示限流閾值,即每秒鐘最多可以處理多少個(gè)請(qǐng)求;grade 表示限流模式,QPS(每秒鐘最多允許通過(guò)的請(qǐng)求數(shù)量);strategy 表示限流策略;controlBehavior 表示流量控制的行為。
接下來(lái),我們需要通過(guò)執(zhí)行如下代碼初始化 Sentinel:
List<FlowRule> rules = new ArrayList<>(); rules.add(rule1); rules.add(rule2); FlowRuleManager.loadRules(rules);
我們這里定義了一個(gè) FlowRule 數(shù)組,將前面定義好的兩個(gè)規(guī)則加入到列表中,然后通過(guò) FlowRuleManager.loadRules() 方法加載這些規(guī)則。
現(xiàn)在,我們可以在查詢(xún)用戶(hù)信息的方法上增加 @SentinelResource 注解,并在該注解中設(shè)置 blockHandler 和 fallback 屬性來(lái)處理限流和降級(jí)異常:
@SentinelResource(value = "queryUser", blockHandler = "queryUserBlockHandler",
fallback = "queryUserFallback")
public UserInfo queryUser(String userId) {
// 查找用戶(hù)信息的實(shí)現(xiàn)
}
// 限流/降級(jí)處理函數(shù)
public UserInfo queryUserBlockHandler(String userId, BlockException ex) {
// 返回具體的錯(cuò)誤信息
}
// 降級(jí)處理
public UserInfo queryUserFallback(String userId, Throwable ex) {
// 返回降級(jí)后的響應(yīng)
}以上代碼中我們定義了一個(gè)名為“queryUser”的資源,它被 @SentinelResource 注解所修飾,blockHandler 屬性表示當(dāng)該服務(wù)觸發(fā)限流或降級(jí)時(shí)調(diào)用的函數(shù),fallback 屬性表示服務(wù)出現(xiàn)異常時(shí)的回退函數(shù)。
最后,我們可以通過(guò)對(duì)定時(shí)任務(wù)進(jìn)行調(diào)度,模擬10秒內(nèi)對(duì)同一個(gè) API 請(qǐng)求用戶(hù)數(shù)據(jù)的場(chǎng)景,例如代碼如下:
public class QueryUserTask implements Runnable {
private static final Random random = new Random();
@Override
public void run() {
// 模擬 10 秒內(nèi)對(duì)同一個(gè) API 請(qǐng)求用戶(hù)數(shù)據(jù)
for (int i = 0; i < 20; i++) {
String userId = "user-" + (i % 5);
queryUser(userId);
try {
Thread.sleep(random.nextInt(500));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}我們可以在 QueryUserTask 內(nèi)部實(shí)現(xiàn)每隔一秒獲取一次用戶(hù)信息,檢測(cè)系統(tǒng)是否觸發(fā)限流或降級(jí)保護(hù)。如果觸發(fā)了規(guī)則中配置的限流規(guī)則,那么 Sentinel 將執(zhí)行相應(yīng)的措施進(jìn)行處理。
好了,本篇文章就先分享到這里了,后續(xù)將會(huì)繼續(xù)介紹sentinel詳細(xì)的其他方面的知識(shí)。
到此這篇關(guān)于使用Sentinel滑動(dòng)窗口實(shí)現(xiàn)限流和降級(jí)的文章就介紹到這了,更多相關(guān)Sentinel限流和降級(jí)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot3 集成 Spring AI 實(shí)現(xiàn) A
Spring AI的Advisor API是一種聲明式的攔截機(jī)制,借鑒了 Spring AOP 的設(shè)計(jì)理念,允許開(kāi)發(fā)者在AI交互的生命周期關(guān)鍵節(jié)點(diǎn)插入自定義邏輯,本文全面介紹了Spring Boot集成Spring AI 1.0.0 實(shí)現(xiàn) Advisor 增強(qiáng)機(jī)制的完整流程,感興趣的朋友跟隨小編一起看看吧2026-03-03
定時(shí)任務(wù)@Scheduled用法及其參數(shù)使用
這篇文章主要介紹了定時(shí)任務(wù)@Scheduled用法及其參數(shù)使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
用java實(shí)現(xiàn)斗地主發(fā)牌過(guò)程
這篇文章主要為大家詳細(xì)介紹了用java實(shí)現(xiàn)斗地主發(fā)牌過(guò)程,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-11-11
java中構(gòu)造器內(nèi)部調(diào)用構(gòu)造器實(shí)例詳解
在本篇文章里小編給大家分享的是關(guān)于java中構(gòu)造器內(nèi)部調(diào)用構(gòu)造器實(shí)例內(nèi)容,需要的朋友們可以學(xué)習(xí)下。2020-05-05
Spring?component-scan?XML配置與@ComponentScan注解配置
這篇文章主要介紹了Spring?component-scan?XML配置與@ComponentScan注解配置,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09
PostMan傳@RequestParam修飾的數(shù)組方式
這篇文章主要介紹了PostMan傳@RequestParam修飾的數(shù)組方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08
從千千靜聽(tīng)歌詞服務(wù)器獲取lrc歌詞示例分享
這篇文章主要介紹了使用PHP從千千靜聽(tīng)歌詞服務(wù)器獲取lrc歌詞的方法,大家參考使用吧2014-01-01

