日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

限流该怎么做?

發布時間:2025/4/5 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 限流该怎么做? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

https://www.infoq.cn/article/UhixHoWebU_TYJewJwcL

有熔斷機制的系統,它對可用性的作用至少保證了不會全盤崩潰。

但是你可以想象一個稍微極端一點的場景,如果系統流量不是很穩定,導致頻繁觸發熔斷的話,是不是意味著系統一直熔斷的三種狀態中不斷切換。

導致的結果是每次從開啟熔斷到關閉熔斷的期間,必然會導致大量的用戶無法正常使用。系統層面的可用性大致是這樣的。

另外,從資源利用率上也會很容易發現,波谷的這段時期資源是未充分利用的。

由此可見,光有熔斷是遠遠不夠的。

在高壓下,只要系統沒宕機,如果能將接收的流量持續保持在高位,但又不超過系統所能承載的上限,會是更有效率的運作模式,因為會將這里的波谷填滿。

在如今的互聯網已經作為社會基礎設施的大環境下,上面的這個場景其實離我們并不是那么遠,同時也會顯得沒那么極端。例如,層出不窮的營銷玩法,一個接著一個的社會熱點,以及互聯網冰山之下的黑產、刷子的蓬勃發展,更加使得這個場景變的那么的需要去考慮、去顧忌。因為隨時都有可能會涌入超出你預期的流量,然后壓垮你的系統。

那么限流的作用就很顯而易見了:只要系統沒宕機,系統只是因為資源不夠,而無法應對大量的請求,為了保證有限的系統資源能夠提供最大化的服務能力,因而對系統按照預設的規則進行流量(輸出或輸入)限制的一種方法,確保被接收的流量不會超過系統所能承載的上限。

一、怎么做「限流」

從前面聊到的內容中我們也知道,限流最好能“限”在一個系統處理能力的上限附近,所以:

  • 通過「壓力測試」等方式獲得系統的能力上限在哪個水平是第一步。
  • 其次,就是制定干預流量的策略。比如標準該怎么定、是否只注重結果還是也要注重過程的平滑性等。
  • 最后,就是處理“被干預掉”的流量。能不能直接丟棄?不能的話該如何處理?
  • 獲得系統能力的上限

    第一步不是我們這次內容的重點,說起來就是對系統做一輪壓測。可以在一個獨立的環境進行,也可以直接在生產環境的多個節點中選擇一個節點作為樣本來壓測,當然需要做好與其他節點的隔離。

    一般我們做壓測為了獲得 2 個結果,「速率」和「并發數」。前者表示在一個時間單位內能夠處理的請求數量,比如 xxx 次請求 / 秒。后者表示系統在同一時刻能處理的最大請求數量,比如 xxx 次的并發。從指標上需要獲得「最大值」、「平均值」或者「中位數」。后續限流策略需要設定的具體標準數值就是從這些指標中來的。

    題外話:從精益求精的角度來說,其他的諸如 cpu、網絡帶寬以及內存的耗用也可以作為參照因素。

    制定干預流量的策略

    常用的策略就 4 種,我給它起了一個簡單的定義——「兩窗兩桶」。兩窗就是:固定窗口、滑動窗口,兩桶就是:漏桶、令牌桶。

    固定窗口

    固定窗口就是定義一個“固定”的統計周期,比如 1 分鐘或者 30 秒、10 秒這樣。然后在每個周期統計當前周期中被接收到的請求數量,經過計數器累加后如果達到設定的閾值就觸發「流量干預」。直到進入下一個周期后,計數器清零,流量接收恢復正常狀態。

    這個策略最簡單,寫起代碼來也沒幾行。

    復制代碼
    ? 全局變量 int totalCount = 0; // 有一個「固定周期」會觸發的定時器將數值清零。
    ??
    ? if(totalCount > 限流閾值) {
    ? return; // 不繼續處理請求。
    ? }
    ? totalCount++;
    ??
    ? // do something...

    固定窗口有一點需要注意的是,假如請求的進入非常集中,那么所設定的「限流閾值」等同于你需要承受的最大并發數。所以,如果需要顧忌到并發問題,那么這里的「固定周期」設定的要盡可能的短。因為,這樣的話「限流閾值」的數值就可以相應的減小。甚至,限流閾值就可以直接用并發數來指定。比如,假設固定周期是 3 秒,那么這里的閾值就可以設定為「平均并發數 *3」。

    不過不管怎么設定,固定窗口永遠存在的缺點是:由于流量的進入往往都不是一個恒定的值,所以一旦流量進入速度有所波動,要么計數器會被提前計滿,導致這個周期內剩下時間段的請求被“限制”。要么就是計數器計不滿,也就是「限流閾值」設定的過大,導致資源無法充分利用。

    「滑動窗口」可以改善這個問題。

    滑動窗口

    滑動窗口其實就是對固定窗口做了進一步的細分,將原先的粒度切的更細,比如 1 分鐘的固定窗口切分為 60 個 1 秒的滑動窗口。然后統計的時間范圍隨著時間的推移同步后移。

    同時,我們還可以得出一個結論是:如果固定窗口的「固定周期」已經很小了,那么使用滑動窗口的意義也就沒有了。舉個例子,現在的固定窗口周期已經是 1 秒了,再切分到毫秒級別能反而得不償失,會帶來巨大的性能和資源損耗。

    滑動窗口大致的代碼邏輯是這樣:

    復制代碼
    ? 全局數組 鏈表 [] counterList = new 鏈表 [切分的滑動窗口數量];
    ? // 有一個定時器,在每一次統計時間段起點需要變化的時候就將索引 0 位置的元素移除,并在末端追加一個新元素。
    ??
    ? int sum = counterList.Sum();
    ? if(sum > 限流閾值) {
    ? return; // 不繼續處理請求。
    ? }
    ??
    ? int 當前索引 = 當前時間的秒數 % 切分的滑動窗口數量 ;
    ? counterList[當前索引]++;
    ??
    ? // do something...

    雖然說滑動窗口可以改善這個問題,但是本質上還是預先劃定時間片的方式,屬于一種“預測”,意味著幾乎肯定無法做到 100% 的物盡其用。

    但是,「桶」模式可以做的更好,因為「桶」模式中多了一個緩沖區(桶本身)。

    漏桶

    首先聊聊「漏桶」吧。漏桶模式的核心是固定“出口”的速率,不管進來多少量,出去的速率一直是這么多。如果涌入的量多到桶都裝不下了,那么就進行「流量干預」。

    整個實現過程我們來分解一下。

  • 控制流出的速率。這個其實可以使用前面提到的兩個“窗口”的思路來實現。如果當前速率小于閾值則直接處理請求,否則不直接處理請求,進入緩沖區,并增加當前水位。
  • 緩沖的實現可以做一個短暫的休眠或者記錄到一個容器中再做異步的重試。
  • 最后控制桶中的水位不超過最大水位。這個很簡單,就是一個全局計數器,進行加加減減。
  • 這樣一來,你會發現本質就是:通過一個緩沖區將不平滑的流量“整形”成平滑的(高于均值的流量暫存下來補足到低于均值的時期),以此最大化計算處理資源的利用率。

    實現代碼的簡化表示如下:

    復制代碼
    ? 全局變量 int unitSpeed; // 出口當前的流出速率。每隔一個速率計算周期(比如 1 秒)會觸發定時器將數值清零。
    ? 全局變量 int waterLevel; // 當前緩沖區的水位線。
    ??
    ? if(unitSpeed < 速率閾值) {
    ? unitSpeed++;
    ??
    ? //do something...
    ? }
    ? else{
    ? if(waterLevel > 水位閾值){
    ? return; // 不繼續處理請求。
    ? }
    ??
    ? waterLevel++;
    ??
    ? while(unitSpeed >= 速率閾值){
    ? sleep(一小段時間)。
    ? }
    ? unitSpeed++;
    ? waterLevel--;
    ??
    ? //do something...
    ? }

    更優秀的「漏桶」策略已經可以在流量的總量充足的情況下發揮你所預期的 100% 處理能力,但這還不是極致。

    你應該知道,一個程序所在的運行環境中,往往不單單只有這個程序本身,會存在一些系統進程甚至是其它的用戶進程。也就是說,程序本身的處理能力是會被干擾的,是會變化的。所以,你可以預估某一個階段內的平均值、中位數,但無法預估具體某一個時刻的程序處理能力。又因此,你必然會使用相對悲觀的標準去作為閾值,防止程序超負荷。

    那么從資源利用率來說,有沒有更優秀的方案呢?有,這就是「令牌桶」。

    令牌桶

    令牌桶模式的核心是固定“進口”速率。先拿到令牌,再處理請求,拿不到令牌就被「流量干預」。因此,當大量的流量進入時,只要令牌的生成速度大于等于請求被處理的速度,那么此刻的程序處理能力就是極限。

    也來分解一下它的實現過程。

  • 控制令牌生成的速率,并放入桶中。這個其實就是單獨一個線程在不斷的生成令牌。
  • 控制桶中待領取的令牌水位不超過最大水位。這個和「漏桶」一樣,就是一個全局計數器,進行加加減減。
  • 大致的代碼簡化表示如下(看上去像「固定窗口」的反向邏輯):

    全局變量 int tokenCount = 令牌數閾值 ; // 可用令牌數。有一個獨立的線程用固定的頻率增加這個數值,但不大于「令牌數閾值」。

    復制代碼
    ? if(tokenCount == 0){
    ? return; // 不繼續處理請求。
    ? }
    ??
    ? tokenCount--;
    ??
    ? //do something...

    聰明的你可能也會想到,這樣一來令牌桶的容量大小理論上就是程序需要支撐的最大并發數。的確如此,假設同一時刻進入的流量將令牌取完,但是程序來不及處理,將會導致事故發生。

    所以,沒有真正完美的策略,只有合適的策略。因此,根據不同的場景能夠識別什么是最合適的策略是更需要鍛煉的能力。下面 z 哥分享一些我個人的經驗。

    二、做「限流」的最佳實踐

    四種策略該如何選擇?

    首先,固定窗口。一般來說,如非時間緊迫,不建議選擇這個方案,太過生硬。但是,為了能快速止損眼前的問題可以作為臨時應急的方案。

    其次,滑動窗口。這個方案適用于對異常結果「高容忍」的場景,畢竟相比“兩窗”少了一個緩沖區。但是,勝在實現簡單。

    然后,漏桶。z 哥覺得這個方案最適合作為一個通用方案。雖說資源的利用率上不是極致,但是「寬進嚴出」的思路在保護系統的同時還留有一些余地,使得它的適用場景更廣。

    最后,令牌桶。當你需要盡可能的壓榨程序的性能(此時桶的最大容量必然會大于等于程序的最大并發能力),并且所處的場景流量進入波動不是很大(不至于一瞬間取完令牌,壓垮后端系統)。

    分布式系統中帶來的新挑戰

    一個成熟的分布式系統大致是這樣的。

    每一個上游系統都可以理解為是其下游系統的客戶端。然后我們回想一下前面的內容,可能你發現了,前面聊的「限流」都沒有提到到底是在客戶端做限流還是服務端做,甚至看起來更傾向是建立在服務端的基礎上做。但是你知道,在一個分布式系統中,一個服務端本身就可能存在多個副本,并且還會提供給多個客戶端調用,甚至其自身也會作為客戶端角色。那么,在如此交錯復雜的一個環境中,該如何下手做限流呢?我的思路是通過「一縱一橫」來考量。

    都知道「限流」是一個保護措施,那么可以將它想象成一個盾牌。另外,一個請求在系統中的處理過程是鏈式的。那么,正如古時候軍隊打仗一樣,盾牌兵除了有小部分在老大周圍保護,剩下的全在最前線。因為盾的位置越前,能受益的范圍越大。

    分布式系統中最前面的是什么?接入層。如果你的系統有接入層,比如用 nginx 做的反向代理。那么可以通過它的 ngx_http_limit_conn_module 以及 ngx_http_limit_req_module 來做限流,是很成熟的一個解決方案。

    如果沒有接入層,那么只能在應用層以 AOP 的思路去做了。但是,由于應用是分散的,出于成本考慮你需要針對性的去做限流。比如 ToC 的應用必然比 ToB 的應用更需要做,高頻的緩存系統必然比低頻的報表系統更需要做,Web 應用由于存在 Filter 的機制做起來必然比 Service 應用更方便。

    那么應用間的限流到底是做到客戶端還是服務端呢?

    z 哥的觀點是,從效果上客戶端模式肯定是優于服務端模式的,因為當處于被限流狀態的時候,客戶端模式連建立連接的動作都省了。另一個潛在的好處是,與集中式的服務端模式相比,可以把少數的服務端程序的壓力分散掉。但是在客戶端做成本也更高,因為它是去中心化的,假如需要多個節點之間的數據共通的話,是一個很麻煩的事情。

    所以,最終 z 哥建議你:如果考慮成本就服務端模式,考慮效果就客戶端模式。當然也不是絕對,比如一個服務端的流量大部分都來源于某一個客戶端,那么就可以直接在這個客戶端做限流,這也不失為一個好方案。

    數據庫層面的話,一般連接字符串中本身就會包含「最大連接數」的概念,就可以起到限流的作用。如果想做更精細的控制就只能做到統一封裝的數據庫訪問層框架中了。

    聊完了「縱」,那么「橫」是什么呢?

    不管是多個客戶端,還是同一個服務端的多個副本。每個節點的性能必然會存在差異,如何設立合適的閾值?以及如何讓策略的變更盡可能快的在集群中的多個節點生效?說起來很簡單,引入一個性能監控平臺和配置中心。但這些真真要做好不容易,后續我們再展開這塊內容。

    三、總結
    限流就好比保險絲,根據你制定的標準,達到了就拉閘。

    不過,觸發限流后的措施除了直接丟棄請求之外,還有一個方式是「降級」,那么降級有哪些方式呢?我們下一篇再聊吧。

    轉載于:https://www.cnblogs.com/davidwang456/articles/10132640.html

    總結

    以上是生活随笔為你收集整理的限流该怎么做?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 欧美大片黄色 | 黄色视屏网站 | 性欧美视频 | 中文字幕免费播放 | 日日干日日插 | 少妇真实被内射视频三四区 | 亚洲福利专区 | 日韩欧美xxxx| 欧美一级一区 | 无码人妻精品一区二区中文 | 久久免费成人 | 伊人影视在线 | 少妇淫片 | 综合激情久久 | 91成人在线观看喷潮动漫 | 婷婷综合激情网 | 污视频在线播放 | 日日爽视频 | 久久久网站 | 日韩精品免费一区二区三区 | 久久久久久伊人 | 日韩人妻一区二区三区蜜桃 | 男女视频在线观看免费 | 亚洲国产精品久久久久久久 | 精品一区二区三区免费毛片 | 91春色| 日韩一区久久 | 欧美激情免费看 | 奇米影视av | 色人阁在线视频 | 国产成人精品无码片区在线 | 成人免费视频国产免费麻豆 | 玖玖爱精品 | 欧美日韩国产高清视频 | 国产精品ⅴa有声小说 | av在线不卡免费观看 | 午夜中出 | 欧美美女性生活视频 | 看片网站在线观看 | 国产成人精品一二三区 | 国产精品一区二区三区久久 | 午夜小视频在线播放 | 国产高潮网站 | 操操操干干干 | 国产肥白大熟妇bbbb视频 | 久久久久久久久综合 | 久久久久久久九九九九 | 久久男人| 欧美顶级少妇做爰hd | 国产一区av在线 | 国产精品一区二区久久毛片 | 日韩一区二区三区精品 | 日本美女高潮 | 日韩一中文字幕 | 少妇户外露出[11p] | 久久久久亚洲AV成人无码国产 | 久一区二区三区 | 久久久久久久久免费视频 | 女人毛片视频 | 福利国产片 | 久久riav| 亚洲红桃视频 | 免费网站91 | 超黄av | 天堂av8在线 | 毛片网站在线看 | 91久久人澡人人添人人爽欧美 | 香蕉尹人 | 99有精品 | 亚洲性久久 | 顶级黑人搡bbw搡bbbb搡 | 久久久国产精品人人片 | 日韩在线视频网址 | 澳门黄色| 日韩激情在线观看 | 精品久久久久久久久久岛国gif | 伊人9999| 成人福利在线免费观看 | 亚洲第一在线视频 | 日韩毛片无码永久免费看 | 性欧美视频在线观看 | 黄瓜视频污在线观看 | 黄色在线观看免费 | 中文字幕超清在线观看 | 欧美日韩中文国产 | 国产精品s色 | 美女黄色一级片 | 69精品国产 | 爱爱高潮视频 | 日批免费观看视频 | 中文字幕视频在线观看 | 午夜一区二区三区在线 | 免费看日韩毛片 | 国产15页| 国产日韩精品在线 | 伊人影视久久 | 日韩久久久久久久久久久 | 懂色av粉嫩av蜜乳av | 德国经典free性复古xxxx |