分布式降級,限流,熔斷


預防機制
在開發高並發系統時有三把利器用來保護系統:緩存、降級和限流。
緩存:
目的是提升系統訪問速度和增大系統能處理的容量,在實際的開發過程中,針對於一些基礎檔案類數據或者配置參數類數據,我們一般用緩存讀取,原因是這些數據的變化性不大,這一部分我們可以減少和數據庫的IO交互
 
緩存失效分為幾種場景:1.緩存服務掛了 2.高分期緩存失效 3.熱點緩存失效
解決方案:注意這里的校驗是兩次,這里參照單列模式的DCL雙重校驗鎖機制。(嗯....講道理這里要整一個volatile 內存屏障 )

 
降級:
降級是指在某些高並發場景下,把某些非核心的業務統統往下調。諸如雙11交易時,查看螞蟻深林,螞蟻庄園之類的服務,僅僅顯示一百條數據。
當然降級的顆粒度 ,可以自由調配,根據實際業務和當前的服務器並發請求。比如說,你也可以限制數據庫的跟新與插入,但是允許查詢操作。
從RPC的角度來說,我訪問的是本地服務的偽裝者,而不是應用服務本身。
 
限流:
限流指的是降低一定時間內的並發訪問量  一般兩種做法 一種是拉長時間,一種是降低訪問QPS()
一般開發高並發系統常見的限流有:限制總並發數(比如數據庫連接池、線程池)、限制瞬時並發數(如nginx的limit_conn模塊,用來限制瞬時並發連接數)、限制時間窗口內的平均速率(如Guava的RateLimiter、nginx的limit_req模塊,限制每秒的平均速率);其他還有如限制遠程接口調用速率、限制MQ的消費速率。另外還可以根據網絡連接數、網絡流量、CPU或內存負載等來限流。
 
限流算法:
限流算法一般分為以下幾種:滑動窗口,漏桶,令牌桶.
 

滑動窗口:
    發送和接受方都會維護一個數據幀的序列,這個序列被稱作窗口。發送方的窗口大小由接受方確定,目的在於控制發送速度,以免接受方的緩存不夠大,而導致溢出,同時控制流量也可以避免網絡擁塞。下面圖中的4,5,6號數據幀已經被發送出去,但是未收到關聯的ACK,7,8,9幀則是等待發送。可以看出發送端的窗口大小為6,這是由接受端告知的。此時如果發送端收到4號ACK,則窗口的左邊緣向右收縮,窗口的右邊緣則向右擴展,此時窗口就向前滑動了,即數據幀10也可以被發送。

這個是滑動窗口的演示地址,很形象
https://media.pearsoncmg.com/aw/ecs_kurose_compnetwork_7/cw/content/interactiveanimations/selective-repeat-protocol/index.html

 

 

滑動窗口計數器算法是限流算法里最簡單也是最容易實現的一種算法。比如我們規定,對於A接口來說,我們1分鍾的訪問次數不能超過100個。那么我們可以這么做:在一開 始的時候,我們可以設置一個計數器counter,每當一個請求過來的時候,counter就加1,如果counter的值大於100並且該請求與第一個 請求的間隔時間還在1分鍾之內,那么說明請求數過多;如果該請求與第一個請求的間隔時間大於1分鍾,且counter的值還在限流范圍內,那么就重置 counter,具體算法的示意圖如下:

 

 

漏桶(控制傳輸速率 leaky bucket):
漏桶算法思路是,不斷的往桶里面注水,無論注水的速度是大還是小,水都是按固定的速率往外漏水;如果桶滿了,水會溢出;
桶本身具有一個恆定的速率往下漏水,而上方時快時慢的會有水進入桶內。當桶還未滿時,上方的水可以加入。一旦水滿,上方的水就無法加入。
桶滿正是算法中的一個關鍵的觸發條件(即流量異常判斷成立的條件)。而此條件下如何處理上方流下來的水,有兩種方式
在桶滿水之后,常見的兩種處理方式為:
1)暫時攔截住上方水的向下流動,等待桶中的一部分水漏走后,再放行上方水。
2)溢出的上方水直接拋棄。
特點
1. 漏水的速率是固定的
2. 即使存在突然注水量變大的情況,漏水的速率也是固定的
 

 

 

令牌桶(解決突發流量)
 
令牌桶算法是網絡流量整形(Traffiffiffic Shaping)和速率限制(Rate Limiting)中最常使用的一種算法。典型情況下,令牌桶算法用來控制發送到網絡上的數據的數目,並允許突發數據的發送。
令牌桶是一個存放固定容量令牌(token)的桶,按照固定速率往桶里添加令牌; 令牌桶算法實際上由三部分組成:兩個流和一個桶,分別是令牌流、數據流和令牌桶
 
令牌流與令牌桶
系統會以一定的速度生成令牌,並將其放置到令牌桶中,可以將令牌桶想象成一個緩沖區(可以用隊列這種數據結構來實現),當緩沖區填滿的時候,新生成的令牌會被扔掉。
這里有兩個變量很重要:第一個是生成令牌的速度,一般稱為 rate 。比如,我們設定 rate=2 ,即每秒鍾生成 2 個令牌,也就是每 1/2 秒生成一個令牌;
第二個是令牌桶的大小,一般稱為 burst 。比如,我們設定 burst=10 ,即令牌桶最大只能容納 10 個令牌。

有以下三種情形可能發生:
數據流的速率 等於 令牌流的速率。這種情況下,每個到來的數據包或者請求都能對應一個令牌,然后無延遲地通過隊列;
數據流的速率 小於 令牌流的速率。通過隊列的數據包或者請求只消耗了一部分令牌,剩下的令牌會在令牌桶里積累下來,直到桶被裝滿。剩下的令牌可以在突發請求的時候消耗掉。
數據流的速率 大於 令牌流的速率。這意味着桶里的令牌很快就會被耗盡。導致服務中斷一段時間,如果數據包或者請求持續到來,將發生丟包或者拒絕響應。
 

 
處理機制
 
熔斷:
熔斷機制是應對雪崩效應的一種微服務鏈路保護機制。在微服務中,扇出的微服務不可用或者相應時間過長的話會對服務降級,進而熔斷該服務節點,快速返回錯誤信息,釋放資源。
而當檢測到微服務響應正常后,則恢復調用。
 
隔離:
這種模式就像對系統請求按類型划分成一個個小島的一樣,當某個小島被火燒光了,不會影響到其他的小島。
例如可以對不同類型的請求使用線程池來資源隔離,每種類型的請求互不影響,如果一種類型的請求線程資源耗盡,則對后續的該類型請求直接返回,不再調用后續資源。
這種模式使用場景非常多,例如將一個服務拆開,對於重要的服務使用單獨服務器來部署,再或者公司最近推廣的多中心。
 
熔斷設計
在熔斷的設計主要參考了hystrix的做法。其中最重要的是三個模塊:熔斷請求判斷算法、熔斷恢復機制、熔斷報警
(1)熔斷請求判斷機制算法:使用無鎖循環隊列計數,每個熔斷器默認維護10個bucket,每1秒一個bucket,每個blucket記錄請求的成功、失敗、超時、拒絕的狀態,默認錯誤超過50%且10秒內超過20個請求進行中斷攔截。
(2)熔斷恢復:對於被熔斷的請求,每隔5s允許部分請求通過,若請求都是健康的(RT<250ms)則對請求健康恢復。
(3)熔斷報警:對於熔斷的請求打日志,異常請求超過某些設定則報警。
 
隔離設計
隔離的方式一般使用兩種
(1)線程池隔離模式:使用一個線程池來存儲當前的請求,線程池對請求作處理,設置任務返回處理超時時間,堆積的請求堆積入線程池隊列。這種方式需要為每個依賴的服務申請線程池,有一定的資源消耗,好處是可以應對突發流量(流量洪峰來臨時,處理不完可將數據存儲到線程池隊里慢慢處理)
(2)信號量隔離模式:使用一個原子計數器(或信號量)來記錄當前有多少個線程在運行,請求來先判斷計數器的數值,若超過設置的最大線程個數則丟棄改類型的新請求,若不超過則執行計數操作請求來計數器+1,請求返回計數器-1。這種方式是嚴格的控制線程且立即返回模式,無法應對突發流量(流量洪峰來臨時,處理的線程超過數量,其他的請求會直接返回,不繼續去請求依賴的服務)
 
服務降級與熔斷的相關異同點:
相同點:
目的很一致,都是從可用性可靠性着想,為防止系統的整體緩慢甚至崩潰,采用的技術手段;
最終表現類似,對於兩者來說,最終讓用戶體驗到的是某些功能暫時不可達或不可用;
粒度一般都是服務級別,當然,業界也有不少更細粒度的做法,比如做到數據持久層(允許查詢,不允許增刪改);
自治性要求很高,熔斷模式一般都是服務基於策略的自動觸發,降級雖說可人工干預,但在微服務架構下,完全靠人顯然不可能,開關預置、配置中心都是必要手段;
 
區別:
觸發原因不太一樣,服務熔斷一般是某個服務(下游服務)故障引起,而服務降級一般是從整體負荷考慮;
管理目標的層次不太一樣,熔斷其實是一個框架級的處理,每個微服務都需要(無層級之分),而降級一般需要對業務有層級之分(比如降級一般是從最外圍服務開始)
實現方式不太一樣;服務降級具有代碼侵入性(由控制器完成/或自動降級),熔斷一般稱為自我熔斷。
 

基於Redis 實現限流

1、計數算法:
基於redis的incrby 加一和decrby 操作,來控制分布式系統中計數器。

2、令牌桶算法:

基於 Redis 的 list接口可以實現令牌桶令牌補充和令牌消耗操作。


 
參考博客:https://www.jianshu.com/p/c0937bf9849d   
https://blog.csdn.net/llianlianpay/article/details/79768890


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM