剖析sentinel的限流和熔斷

sentinel的限流和熔斷

  • 前言
  • 源碼分析
    • 滑動窗口源碼
    • 限流源碼
    • 熔斷源碼
  • 完結撒花,sentinel源碼還是挺簡單的,如有需要收藏的看官,順便也用發財的小手點點贊哈,如有錯漏,也歡迎各位在評論區評論!

前言

平時發起一個請求,在系統內部微服務之間調用就會形成一條調用鏈路,那對于每個服務要起到保護的作用,如何保護呢?本文就來做一個介紹,筆者平時是使用sentinel居多,是通過其提供的限流和熔斷的措施來保護的,于是文本來剖析sentinel的限流和熔斷;
先介紹雪崩問題:
例如a1服務——》b服務——》c服務;
a2服務——》b服務——》c服務;
a3服務——》b服務;
d服務——》a3服務;
在a1服務調用b時,往下調用c服務,因服務c故障,會占用著b服務連接至超時時間,此時又會有服務a2調b服務,再調c服務,會因服務c故障,繼續堆積連接在b服務上至連接超時,堆積到服務b性能瓶頸也會導致服務b故障,此時a3服務調用b服務也會繼續導致a3服務堆積連接,依次導致所有服務故障,這就是雪崩
市面上解決雪崩的方案:
在這里插入圖片描述
流量控制是限流的,用于保護下游服務,然后其余三種是下游發生了故障的前提下,保護上游服務的方案,其中艙壁模式,也是線程隔離,下游發生故障時,是為調上游的多個服務,建立屬于它們的線程池,仍然會調下游,這樣就會占用著線程;而熔斷降級則不會,下游有問題,例如上游根據調用下游的失敗比例、失敗數來決定觸發熔斷;
所以說流量控制避免雪崩,有了流量控制就不會發生雪崩,而其余三種則解決雪崩問題;

再介紹限流與熔斷的概念:
限流是保護當前服務,提前對服務做了qps限流保護;
熔斷則是某個服務因沒有限流發生了故障,然后上游調用該服務時,不會再調用了,而是在上游定義了關于該服務的降級邏輯,起到保護上游服務的作用,避免因為該服務的故障,導致雪崩問題;

那限流、熔斷、雪崩之間的關系?
更像是因為沒有限流容易導致服務提供方問題,然后服務消費方用熔斷來保護自己,從而避免雪崩;

源碼分析

在 Sentinel 里面,所有的資源都對應一個資源名稱以及一個 Entry。Entry 可以通過對主流框架的適配自動創建,也可以通過注解的方式或調用 API 顯式創建;每一個 Entry 創建的時候,同時也會創建一系列功能插槽(slot chain);
例如服務a——》服務b——》服務c,每個服務就是一個保護資源,默認是一個controller一個保護資源,在一個服務里其實可以有多個保護資源,用SentinelResource注解標識controller往后調的一個個service層的方法即可,sentinel對于保護資源的調用鏈路是如下圖:
在這里插入圖片描述
調用鏈路就是這8個slot,簡單來說就是統計訪問的qps,判斷是否達到觸發限流(FlowSlot)或熔斷(DegradeSlot)閾值,每個slot拋出blockExeception,就代表訪問停止了,就不會觸發往后的slot調用,它是使用責任鏈模式調用的。
在這里插入圖片描述
SentinelResource的切面,主要是調SphU.entry方法

//該方法是查找slot鏈,上面說的slot責任鏈就是指這個鏈
com.alibaba.csp.sentinel.CtSph#entryWithPriority
ProcessorSlot<Object> chain = this.lookProcessChain(resourceWrapper);//lookProcessChain方法:第一次訪問資源時,使用copyOnWrite的方式添加到map中,后面就從map獲取即可
ProcessorSlotChain chain = (ProcessorSlotChain)chainMap.get(resourceWrapper);if (chain == null) {synchronized(LOCK) {chain = (ProcessorSlotChain)chainMap.get(resourceWrapper);if (chain == null) {if (chainMap.size() >= 6000) {return null;}chain = SlotChainProvider.newSlotChain();Map<ResourceWrapper, ProcessorSlotChain> newMap = new HashMap(chainMap.size() + 1);newMap.putAll(chainMap);newMap.put(resourceWrapper, chain);chainMap = newMap;}}}//創建的slotChain是通過spi的方式從METAINFO目錄獲取所有的slotpublic ProcessorSlotChain build() {ProcessorSlotChain chain = new DefaultProcessorSlotChain();List<ProcessorSlot> sortedSlotList = SpiLoader.of(ProcessorSlot.class).loadInstanceListSorted();Iterator var3 = sortedSlotList.iterator();while(var3.hasNext()) {ProcessorSlot slot = (ProcessorSlot)var3.next();if (!(slot instanceof AbstractLinkedProcessorSlot)) {RecordLog.warn("The ProcessorSlot(" + slot.getClass().getCanonicalName() + ") is not an instance of AbstractLinkedProcessorSlot, can't be added into ProcessorSlotChain", new Object[0]);} else {//獲取的每個slot形成一個AbstractLinkedProcessorSlot鏈表,因為每個slot繼承了該類chain.addLast((AbstractLinkedProcessorSlot)slot);}}return chain;}
//創建完slotChain后,就開始執行每個slot
chain.entry(context, resourceWrapper, (Object)null, count, prioritized, args);public class DefaultProcessorSlotChain extends ProcessorSlotChain {AbstractLinkedProcessorSlot<?> first = new AbstractLinkedProcessorSlot<Object>() {//這里是第一個slot,從這里開始調用public void entry(Context context, ResourceWrapper resourceWrapper, Object t, int count, boolean prioritized, Object... args) throws Throwable {super.fireEntry(context, resourceWrapper, t, count, prioritized, args);}public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {super.fireExit(context, resourceWrapper, count, args);}};
}//調用下一個slot是通過當前slot的next屬性(就是下一個slot元素)public void fireEntry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, boolean prioritized, Object... args) throws Throwable {if (this.next != null) {this.next.transformEntry(context, resourceWrapper, obj, count, prioritized, args);}}

這里詳細介紹了slot調用鏈路的過程,本文主要是關注限流和熔斷,所以只需看FlowSlot和DegradeSlot即可;

滑動窗口源碼

是用StatisticSlot統計訪問資源的線程數、qps。
滑動窗口的原理:時間窗口設定qps閾值,先看看固定時間窗的缺點,一個時間窗口內是不會超出閾值,但一個時間窗的后半個時間窗和下一個時間窗的前半個時間窗加起來會超過閾值。于是將一個時間窗劃分為多個時間樣本,例如1s的時間窗劃分為5個樣本時間窗(每個200ms),即使統計到一個時間窗的后半個時間窗和后一個時間窗的前半個時間窗時,會統計每個樣本時間窗來是否達到閾值,從而解決該問題;

注意:樣本時間窗劃分得越小,統計得越準確;

com.alibaba.csp.sentinel.slots.statistic.StatisticSlot#entry//訪問鏈表所有的slotthis.fireEntry(context, resourceWrapper, node, count, prioritized, args);//統計線程數node.increaseThreadNum();//統計qpsnode.addPassRequest(count);

這里有覺得奇怪嗎?先是訪問所有的slot是否通過后(任何一個slot都不拋出BlockException),再統計資源的線程數和qps,其實是類似于elastic search寫文檔時,先寫內存,然后再寫transaction log文件,這樣是為了寫內存成功后再寫入transaction log文件,不至于寫入文件后,再回滾內存。同樣是為了校驗通過后,再統計,不至于統計完才校驗失敗。

基礎知識:

在這里插入圖片描述
這里是時間窗口類

在這里插入圖片描述
時間窗口類包含的屬性,以及包含的時間樣本窗口類WindowWrap

public void addPass(int count) {//獲取當前時間點所在的樣本窗口WindowWrap<MetricBucket> wrap = this.data.currentWindow();//將當前請求的計數量添加到當前樣本窗口的統計數據中((MetricBucket)wrap.value()).addPass(count);
}

就不往里跟了,主要是根據當前時間點統計是在當前時間窗的哪個樣本時間窗里,然后往里添加

限流源碼

在這里插入圖片描述
對應的就是這些規則
是在FlowSlot中,根據staticFlow統計的qps、線程數,來判斷是否達到閾值,從而觸發限流

com.alibaba.csp.sentinel.slots.block.flow.FlowSlot#entry
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args) throws Throwable {//檢測并應用流控規則this.checkFlow(resourceWrapper, context, node, count, prioritized);//觸發下一個slotthis.fireEntry(context, resourceWrapper, node, count, prioritized, args);
}public void checkFlow(Function<String, Collection<FlowRule>> ruleProvider, ResourceWrapper resource, Context context, DefaultNode node, int count, boolean prioritized) throws BlockException {if (ruleProvider != null && resource != null) {//獲取到指定資源的所有流控規則Collection<FlowRule> rules = (Collection)ruleProvider.apply(resource.getName());if (rules != null) {Iterator var8 = rules.iterator();//這個應用流控規則。若是無法通過則拋出異常,后續規則不再應用while(var8.hasNext()) {FlowRule rule = (FlowRule)var8.next();if (!this.canPassCheck(rule, context, node, count, prioritized)) {throw new FlowException(rule.getLimitApp(), rule);}}}}}

熔斷源碼

public class DegradeSlot extends AbstractLinkedProcessorSlot<DefaultNode> {public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args) throws Throwable {this.performChecking(context, resourceWrapper);this.fireEntry(context, resourceWrapper, node, count, prioritized, args);}void performChecking(Context context, ResourceWrapper r) throws BlockException {//獲取當前資源所有熔斷器List<CircuitBreaker> circuitBreakers = DegradeRuleManager.getCircuitBreakers(r.getName());if (circuitBreakers != null && !circuitBreakers.isEmpty()) {Iterator var4 = circuitBreakers.iterator();CircuitBreaker cb;//逐個嘗試所有熔斷器do {if (!var4.hasNext()) {return;}cb = (CircuitBreaker)var4.next();//若沒有通過當前熔斷器,則直接拋出異常} while(cb.tryPass(context));throw new DegradeException(cb.getRule().getLimitApp(), cb.getRule());}}
}

在這里插入圖片描述
一般來說,熔斷降級其實是對于服務的調用方來說的。在項目中會經常調用其它服務或者是第三方接口,而對于這些接口,一旦它們出現不穩定,就有可能導致自身服務長時間等待,從而出現響應延遲等等問題。此時服務調用方就可基于熔斷降級方式解決。一旦第三方接口響應時間過長,那么就可以使用慢調用比例規則,當出現大量長時間響應的情況,那么就直接熔斷,不去請求。雖然說熔斷降級是針對服務的調用方來說,但是Sentinel本身并沒有限制熔斷降級一定是調用其它的服務。

完結撒花,sentinel源碼還是挺簡單的,如有需要收藏的看官,順便也用發財的小手點點贊哈,如有錯漏,也歡迎各位在評論區評論!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/898019.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/898019.shtml
英文地址,請注明出處:http://en.pswp.cn/news/898019.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

硬盤分區誤刪后的數據救贖

一、硬盤分區誤刪的概述 硬盤分區誤刪&#xff0c;是許多電腦用戶在使用過程中可能遭遇的棘手問題。分區&#xff0c;作為硬盤上存儲數據的邏輯單元&#xff0c;一旦被誤刪除&#xff0c;不僅會導致該分區內的所有數據瞬間消失&#xff0c;還可能影響到整個硬盤的存儲結構和數…

代碼隨想錄算法訓練營第三十五天(20250303) |01背包問題 二維,01背包問題 一維,416. 分割等和子集 -[補卡20250316]

01背包問題 二維 鏈接 遍歷物品沒有大小順序要求重點是模擬&#xff0c;推導出遞推公式 #include <iostream> #include <vector>int main(){int m, n;std::cin>>m>>n;std::vector<int> weight(m,0),value(m,0);for(int i{0}; i<m; i){std:…

老牌軟件,方便處理圖片,量大管飽。

今天介紹的圖片查看器名字是&#xff1a;FastStone Image Viewer&#xff0c;是一款可查看、編輯、批量重命名、批量轉換的圖片查看軟件。文末有分享鏈接。 軟件以資源管理器的方式管理你電腦里的圖片&#xff0c;點擊左側可選擇文件夾&#xff0c;右邊可預覽圖片。 軟妹用得最…

【數據庫相關】mysql數據庫巡檢

mysql數據庫巡檢 巡檢步驟**一、基礎狀態檢查****二、服務器資源監控****CPU使用****內存使用****磁盤I/O****網絡流量** **三、數據庫內部健康度****全局狀態****慢查詢監控****鎖與并發** **四、存儲引擎健康****InnoDB引擎****MyISAM引擎** **五、日志與備份****六、安全與權…

Python進階編程總結

&#x1f9d1; 博主簡介&#xff1a;CSDN博客專家&#xff0c;歷代文學網&#xff08;PC端可以訪問&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移動端可微信小程序搜索“歷代文學”&#xff09;總架構師&#xff0c;15年工作經驗&#xff0c;…

Redis復制(replica)主從模式

Redis主從復制 Redis 的復制&#xff08;replication&#xff09;功能允許用戶根據一個 Redis 服務器來創建任意多個該服務器的復制品&#xff0c;其中被復制的服務器為主服務器&#xff08;master&#xff09;&#xff0c;而通過復制創建出來的服務器復制品則為從服務器&#…

Adobe Premiere Pro2023配置要求

Windows 系統 最低配置 處理器&#xff1a;Intel 第六代或更新版本的 CPU&#xff0c;或 AMD Ryzen? 1000 系列或更新版本的 CPU&#xff0c;需要支持 Advanced Vector Extensions 2&#xff08;AVX2&#xff09;。操作系統&#xff1a;Windows 10&#xff08;64 位&#xff…

【Kubernets】Deployment 和 StatefulSet 有什么區別?什么時候用 StatefulSet?

Deployment 和 StatefulSet 的區別 在 Kubernetes 中&#xff0c;Deployment 和 StatefulSet 都用于管理 Pod&#xff0c;但它們適用于不同的場景。 1. Deployment&#xff1a;管理無狀態應用 特點&#xff1a; 無狀態&#xff1a;Pod 之間相互獨立&#xff0c;不需要保持順…

R語言零基礎系列教程-03-RStudio界面介紹與關鍵設置

代碼、講義、軟件回復【R語言03】獲取。 設置位置: 菜單欄 - Tools - Blobal Options 設置 通用設置 設置面板左側General選項 版本選擇: 一般只用一個版本即可 默認工作目錄設置: 你希望RStudio打開時是基于哪個目錄進行工作可以不設置, 因為腳本一般都是放置在特定項目路…

車載以太網測試-9【網絡層】-子網劃分的子網掩碼VLAN

目錄 1 摘要2 子網劃分2.1 子網掩碼2.2 VLAN&#xff08;虛擬局域網&#xff09;2.2.1 IEEE 802.1Q VLAN標簽2.2.1.1 VLAN標簽的結構2.2.1.2 VLAN標簽的插入2.2.1.3 VLAN標簽的處理2.1.2.4 PVID&#xff08;Port VLAN Identifier&#xff09; 和 VID&#xff08;VLAN Identifie…

微信小程序刷題邏輯實現:技術揭秘與實踐分享

頁面展示&#xff1a; 概述 在當今數字化學習的浪潮中&#xff0c;微信小程序以其便捷性和實用性&#xff0c;成為了眾多學習者刷題備考的得力工具。今天&#xff0c;我們就來深入剖析一個微信小程序刷題功能的實現邏輯&#xff0c;從代碼層面揭開其神秘面紗。 小程序界面布局…

JVM--垃圾回收

垃圾回收的概念 垃圾回收主要針對的是堆中的對象&#xff0c;堆是一個共享的區域&#xff0c;創建的對象和數組都放在這個位置。但是我們不能一直的創建對象&#xff0c;也不是所有的對象能一直存放&#xff0c;如果不進行垃圾回收&#xff0c;內存遲早會耗盡&#xff0c;及時…

【教程】繼承中的訪問控制 C++

目錄 簡介public&#xff0c;protected 和 private繼承中的 public&#xff0c;protected 和 private示例 簡介 在 C 中派生類可以通過 public&#xff0c;protected 和 private 三種修飾符決定基類成員在派生類中的訪問級別 public&#xff0c;protected 和 private 公有成…

【2025】基于python+django的駕校招生培訓管理系統(源碼、萬字文檔、圖文修改、調試答疑)

課題功能結構圖如下&#xff1a; 駕校招生培訓管理系統設計 一、課題背景 隨著機動車保有量的不斷增加&#xff0c;人們對駕駛技能的需求也日益增長。駕校作為駕駛培訓的主要機構&#xff0c;面臨著激烈的市場競爭和學員需求多樣化等挑戰。傳統的駕校管理模式往往依賴于人工操作…

要登錄的設備ip未知時的處理方法

目錄 1 應用場景... 1 2 解決方法&#xff1a;... 1 2.1 wireshark設置... 1 2.2 獲取網口mac地址&#xff0c;wireshark抓包前預過濾掉自身mac地址的影響。... 2 2.3 pc網口和設備對接... 3 2.3.1 情況1&#xff1a;... 3 2.3.2 情…

一.ffmpeg打開麥克風,錄制音頻并重采樣

一.windows windows下使用msys編譯ffmpeg&#xff0c;先編譯libx264和libx265&#xff0c;然后編譯ffmpeg的時候需要添加這兩個庫的路徑才能--enable&#xff1b;為什么ffplay--enable了還是沒有呢&#xff0c;仔細看編譯打印&#xff0c;可能剛有一段報錯提示SDL找不到&#…

go 安裝swagger

1、依賴安裝&#xff1a; # 安裝 swag 命令行工具 go install github.com/swaggo/swag/cmd/swaglatest# 安裝 gin-swagger 和 swagger 文件的依賴 go get -u github.com/swaggo/gin-swagger go get -u github.com/swaggo/files 2、測試 cmd中輸入&#xff1a; swag -v 如果…

網絡安全反滲透 網絡安全攻防滲透

網絡滲透防范主要從兩個方面來進行防范&#xff0c;一方面是從思想意識上進行防范&#xff0c;另一方面就是從技術方面來進行防范。 1.從思想意識上防范滲透 網絡攻擊與網絡安全防御是正反兩個方面&#xff0c;縱觀容易出現網絡安全事故或者事件的公司和個人&#xff0c;在這些…

java泛型通配符?及上下界(extends,super)保證安全性、靈活性、可讀性

在 Java 中&#xff0c;泛型通配符&#xff08;?&#xff09;用于表示未知類型&#xff0c;通常用于增強泛型的靈活性。通配符可以與上下限結合使用&#xff0c;以限制泛型的范圍。以下是通配符及上下限的使用示例&#xff1a; 1. 無界通配符 (?) 無界通配符表示可以接受任意…

技術視界|構建理想仿真平臺,加速機器人智能化落地

在近期的 OpenLoong 線下技術分享會 上&#xff0c;松應科技聯合創始人張小波進行了精彩的演講&#xff0c;深入探討了仿真技術在機器人智能化發展中的關鍵作用。他結合行業趨勢&#xff0c;剖析了現有仿真平臺的挑戰&#xff0c;并描繪了未來理想仿真系統的設計理念與實現路徑…