高并發架構設計之限流

一、引言

再強大的系統,也怕流量短事件內集中爆發,就像銀行怕擠兌一樣,所以,高并發另一個必不可少的模塊就是限流。限流是一種通過控制請求的速率或數量來保護系統免受過載的技術。流控的精髓是限制單位時間內的請求量,最大程度保障系統的可靠性及可用性。

二、限流算法

限流是在高并發環境下,為了保護系統的穩定性和可用性而引入的一種策略。通過限制并發請求的數量或頻率,可以防止系統被過多的請求壓垮或耗盡資源。

常見的流控算法包括:固定窗口、滑動窗口、漏桶、令牌桶、滑動日志等算法。

2.1?固定窗口算法(計數器)

固定窗口限流算法(Fixed Window Rate Limiting Algorithm)是一種最簡單的限流算法,其原理是在固定時間窗口(單位時間)內限制請求的數量。

原理

固定窗口是最簡單的流控算法。即,給定時間窗口,維護一個計數器用于統計訪問次數,并實現以下規則:

  1. 如果訪問次數小于閾值,則允許訪問,訪問次數+1;
  2. 如果訪問次數超出閾值,則限制訪問,訪問次數不增;
  3. 如果超過了時間窗口,計數器清零,并重置清零后的首次成功訪問時間為當前時間。

適用場景

  • 保護后端服務免受大流量沖擊,避免服務崩潰;
  • 對 API 調用進行限制,保證公平使用;
  • 防止惡意用戶對服務進行洪水攻擊;

實現方式

public class FixedWindowRateLimiter {private static int counter = 0;  // 統計請求數private static long lastAcquireTime = 0L;private static final long windowUnit = 1000L; // 假設固定時間窗口是1000msprivate static final int threshold = 10; // 窗口閥值是10public synchronized boolean tryAcquire() {long currentTime = System.currentTimeMillis();  // 獲取系統當前時間if (currentTime - lastAcquireTime > windowUnit) {  // 檢查是否在時間窗口內counter = 0;  // 計數器清零lastAcquireTime = currentTime;  // 開啟新的時間窗口}if (counter < threshold) {  // 小于閥值counter++;  // 計數器加1return true;  // 獲取請求成功}return false;  // 超過閥值,無法獲取請求}
}

使用了一個靜態的counter變量來記錄請求數量,lastAcquireTime變量記錄上一次獲取請求的時間戳。windowUnit表示固定時間窗口的長度,threshold則表示在時間窗口內的請求數閥值。

tryAcquire()方法使用了synchronized關鍵字來實現線程安全,在方法中進行以下操作:

  • 獲取當前系統時間 currentTime。
  • 檢查當前時間是否距離上一次獲取請求的時間超過了時間窗口長度 windowUnit。如果超過了時間窗口,則將計數器 counter 清零,并更新 lastAcquireTime 為當前時間,表示進入新的時間窗口。
  • 如果計數器 counter 小于閥值 threshold,則將計數器加1,并返回true表示獲取請求成功。
  • 如果計數器已經達到或超過閥值,則返回false表示無法獲取請求。

優劣分析

優點

  • 固定窗口算法非常簡單,易于實現和理解。
  • 性能高

缺點

  • 存在明顯的臨界問題
  • eg:比如: 假設限流閥值為5個請求,單位時間窗口是1s,如果我們在單位時間內的前0.8-1s1-1.2s,分別并發5個請求。雖然都沒有超過閥值,但是如果算0.8-1.2s內的,則并發數高達10,已經超過單位時間1s不超過5閥值的定義了。

?2.2?滑動窗口算法

為了解決臨界突變問題,可以引入滑動窗口。即:把大的時間窗口拆分成若干粒度更細的子窗口,每個子窗口獨立統計,按子窗口時間滑動,統一限流。當滑動窗口的格子周期劃分的越多,那么滑動窗口的滾動就越平滑,限流的統計就會越精確。

原理

將單位時間周期分為n個小周期,分別記錄每個小周期內接口的訪問次數,并且根據時間滑動刪除過期的小周期。它可以解決固定窗口臨界值的問題。

假設單位時間還是1s,滑動窗口算法把它劃分為5個小周期,也就是滑動窗口(單位時間)被劃分為5個小格子。每格表示0.2s。每過0.2s,時間窗口就會往右滑動一格。然后呢,每個小周期,都有自己獨立的計數器,如果請求是0.83s到達的,0.8~1.0s對應的計數器就會加1

假設我們1s內的限流閥值還是5個請求,0.8~1.0s內(比如0.9s的時候)來了5個請求,落在黃色格子里。

時間過了1.0s這個點之后,又來5個請求,落在紫色格子里。如果是固定窗口算法,是不會被限流的,但是滑動窗口的話,每過一個小周期,它會右移一個小格。過了1.0s這個點后,會右移一小格,當前的單位時間段是0.2~1.2s,這個區域的請求已經超過限定的5了,已觸發限流啦,實際上,紫色格子的請求都被拒絕。

實現方式

import java.util.LinkedList;
import java.util.Queue;
public class SlidingWindowRateLimiter {private Queue<Long> timestamps; // 存儲請求的時間戳隊列private int windowSize; // 窗口大小,即時間窗口內允許的請求數量private long windowDuration; // 窗口持續時間,單位:毫秒public SlidingWindowRateLimiter(int windowSize, long windowDuration) {this.windowSize = windowSize;this.windowDuration = windowDuration;this.timestamps = new LinkedList<>();}public synchronized boolean tryAcquire() {long currentTime = System.currentTimeMillis(); // 獲取當前時間戳// 刪除超過窗口持續時間的時間戳while (!timestamps.isEmpty() && currentTime - timestamps.peek() > windowDuration) {timestamps.poll();}if (timestamps.size() < windowSize) { // 判斷當前窗口內請求數是否小于窗口大小timestamps.offer(currentTime); // 將當前時間戳加入隊列return true; // 獲取請求成功}return false; // 超過窗口大小,無法獲取請求}
}

代碼解讀

在以上代碼中,使用了一個Queue(隊列)來存儲請求的時間戳。構造函數中傳入窗口大小 windowSize 和窗口持續時間 windowDuration。tryAcquire()方法使用了synchronized關鍵字來實現線程安全,在方法中進行以下操作:

  • 獲取當前系統時間戳 currentTime。
  • 從隊列中刪除超過窗口持續時間的時間戳,確保隊列中只保留窗口內的時間戳。
  • 判斷當前窗口內請求數是否小于窗口大小 windowSize。

如果小于窗口大小,將當前時間戳加入隊列,并返回true表示獲取請求成功。如果已經達到或超過窗口大小,表示請求數已滿,返回false表示無法獲取請求。

使用這個滑動窗口限流算法,可以限制在一定時間窗口內的請求頻率,超過窗口大小的請求會被限制。您可以根據實際需求和業務場景進行調整和使用。

適用場景

同固定窗口的場景,且對流量限制要求較高的場景,需要更好地應對突發流量

優劣分析

優勢

  • 簡單易懂
  • 精度高(通過調整時間窗口的大小來實現不同的限流效果)
  • 可擴展性強(可以非常容易地與其他限流算法結合使用)

劣勢

  • 突發流量無法處理(無法應對短時間內的大量請求,但是一旦到達限流后,請求都會直接暴力被拒絕。這樣我們會損失一部分請求,這其實對于產品來說,并不太友好),需要合理調整時間窗口大小。

2.3 漏桶算法

基于(出口)流速來做流控。在網絡通信中常用于流量整形,可以很好地解決平滑度問題。

特點

  • 可以以任意速率流入水滴到漏桶(流入請求)
  • 漏桶具有固定容量,出水速率是固定常量(流出請求)
  • 如果流入水滴超出了桶的容量,則流入的水滴溢出(新請求被拒絕)

原理

思想:將數據包看作是水滴,漏桶看作是一個固定容量的水桶,數據包像水滴一樣從桶的頂部流入桶中,并通過桶底的一個小孔以一定的速度流出,從而限制了數據包的流量

工作原理:對于每個到來的數據包,都將其加入到漏桶中,并檢查漏桶中當前的水量是否超過了漏桶的容量。如果超過了容量,就將多余的數據包丟棄。如果漏桶中還有水,就以一定的速率從桶底輸出數據包,保證輸出的速率不超過預設的速率,從而達到限流的目的。

代碼實現

public class LeakyBucketRateLimiter {private long capacity; // 漏桶容量,即最大允許的請求數量private long rate; // 漏水速率,即每秒允許通過的請求數量private long water; // 漏桶當前水量private long lastTime; // 上一次請求通過的時間戳public LeakyBucketRateLimiter(long capacity, long rate) {this.capacity = capacity;this.rate = rate;this.water = 0;this.lastTime = System.currentTimeMillis();}public synchronized boolean tryAcquire() {long now = System.currentTimeMillis();long elapsedTime = now - lastTime;// 計算漏桶中的水量water = Math.max(0, water - elapsedTime * rate / 1000);if (water < capacity) { // 判斷漏桶中的水量是否小于容量water++; // 漏桶中的水量加1lastTime = now; // 更新上一次請求通過的時間戳return true; // 獲取請求成功}return false; // 漏桶已滿,無法獲取請求}
}

代碼解讀

在以上代碼中,capacity表示漏桶的容量,即最大允許的請求數量;rate表示漏水速率,即每秒允許通過的請求數量。water表示漏桶中當前的水量,lastTime表示上一次請求通過的時間戳。tryAcquire()方法使用了synchronized關鍵字來實現線程安全,在方法中進行以下操作:

  1. 獲取當前系統時間戳 now。
  2. 計算從上一次請求通過到當前的時間間隔 elapsedTime。
  3. 根據漏水速率和時間間隔,計算漏桶中的水量。
  4. 判斷漏桶中的水量是否小于容量。

如果小于容量,漏桶中的水量加1,更新上一次請求通過的時間戳,并返回true表示獲取請求成功。如果已經達到或超過容量,漏桶已滿,返回false表示無法獲取請求。

適用場景

一般用于保護第三方的系統,比如自身的系統需要調用第三方的接口,為了保護第三方的系統不被自身的調用打垮,便可以通過漏斗算法進行限流,保證自身的流量平穩的打到第三方的接口上。

優劣分析

優勢

  • 可以平滑限制請求的處理速度,避免瞬間請求過多導致系統崩潰或者雪崩。
  • 可以控制請求的處理速度,使得系統可以適應不同的流量需求,避免過載或者過度閑置。
  • 可以通過調整桶的大小和漏出速率來滿足不同的限流需求,可以靈活地適應不同的場景。

劣勢

  • 需要對請求進行緩存,會增加服務器的內存消耗。
  • 對于流量波動比較大的場景,需要較為靈活的參數配置才能達到較好的效果。
  • 但是面對突發流量的時候,漏桶算法還是循規蹈矩地處理請求,這不是我們想看到的啦。流量變突發時,我們肯定希望系統盡量快點處理請求,提升用戶體驗嘛。

2.4?令牌桶算法

基于(入口)流速來做流控的一種限流算法。

原理

該算法維護一個固定容量的令牌桶,每秒鐘會向令牌桶中放入一定數量的令牌。當有請求到來時,如果令牌桶中有足夠的令牌,則請求被允許通過并從令牌桶中消耗一個令牌,否則請求被拒絕。

?實現方式

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;import java.util.concurrent.TimeUnit;
public class TokenBucketRateLimiter {private long capacity; // 令牌桶容量,即最大允許的請求數量private long rate; // 令牌產生速率,即每秒產生的令牌數量private long tokens; // 當前令牌數量private ScheduledExecutorService scheduler; // 調度器public TokenBucketRateLimiter(long capacity, long rate) {this.capacity = capacity;this.rate = rate;this.tokens = capacity;this.scheduler = new ScheduledThreadPoolExecutor(1);scheduleRefill(); // 啟動令牌補充任務}private void scheduleRefill() {scheduler.scheduleAtFixedRate(() -> {synchronized (this) {tokens = Math.min(capacity, tokens + rate); // 補充令牌,但不超過容量}}, 1, 1, TimeUnit.SECONDS); // 每秒產生一次令牌}public synchronized boolean tryAcquire() {if (tokens > 0) { // 判斷令牌數量是否大于0tokens--; // 消耗一個令牌return true; // 獲取請求成功}return false; // 令牌不足,無法獲取請求}
}

代碼解讀

capacity表示令牌桶的容量,即最大允許的請求數量;rate表示令牌產生速率,即每秒產生的令牌數量。tokens表示當前令牌數量,scheduler是用于調度令牌補充任務的線程池。在構造方法中,初始化令牌桶的容量和當前令牌數量,并啟動令牌補充任務scheduleRefill()。

scheduleRefill()方法使用調度器定期執行令牌補充任務,每秒補充一次令牌。在補充任務中,通過加鎖的方式更新令牌數量,確保線程安全。補充的令牌數量為當前令牌數量加上產生速率,但不超過令牌桶的容量。

tryAcquire()方法使用synchronized關鍵字來實現線程安全,在方法中進行以下操作:

1.判斷令牌數量是否大于0。

  • 如果令牌數量大于0,表示令牌足夠,消耗一個令牌,并返回true表示獲取請求成功。
  • 如果令牌數量為0,表示令牌不足,返回false表示無法獲取請求。

GuavaRateLimiter限流組件,就是基于令牌桶算法實現的。

適用場景

一般用于保護自身的系統,對調用者進行限流,保護自身的系統不被突發的流量打垮。如果自身的系統實際的處理能力強于配置的流量限制時,可以允許一定程度的流量突發,使得實際的處理速率高于配置的速率,充分利用系統資源。

優劣分析

優勢

  • 穩定性高:令牌桶算法可以控制請求的處理速度,可以使系統的負載變得穩定。
  • 精度高:令牌桶算法可以根據實際情況動態調整生成令牌的速率,可以實現較高精度的限流。
  • 彈性好:令牌桶算法可以處理突發流量,可以在短時間內提供更多的處理能力,以處理突發流量。

劣勢

  • 實現復雜:相對于固定窗口算法等其他限流算法,令牌桶算法的實現較為復雜。對短時請求難以處理:在短時間內有大量請求到來時,可能會導致令牌桶中的令牌被快速消耗完,從而限流。這種情況下,可以考慮使用漏桶算法。
  • 時間精度要求高:令牌桶算法需要在固定的時間間隔內生成令牌,因此要求時間精度較高,如果系統時間不準確,可能會導致限流效果不理想。

2.5?滑動日志算法(比較冷門)

滑動日志限速算法需要記錄請求的時間戳,通常使用有序集合來存儲,我們可以在單個有序集合中跟蹤用戶在一個時間段內所有的請求。

原理

滑動日志算法可以用于實現限流功能,即控制系統在單位時間內處理請求的數量,以保護系統免受過載的影響。以下是滑動日志算法用于限流的原理:

  1. 劃分時間窗口:將時間劃分為固定的時間窗口,例如每秒、每分鐘或每小時等。
  2. 維護滑動窗口:使用一個滑動窗口來記錄每個時間窗口內的請求次數。這個滑動窗口可以是一個固定長度的隊列或數組。
  3. 請求計數:當一個請求到達時,將其計數加一并放入當前時間窗口中。
  4. 滑動:隨著時間的流逝,滑動窗口會根據當前時間窗口的長度,移除最舊的請求計數,并將新的請求計數添加到最新的時間窗口中。
  5. 限流判斷:在每個時間窗口結束時,統計滑動窗口中的請求計數總和,并與預設的閾值進行比較。如果總請求數超過閾值,則觸發限流處理。
  6. 限流處理:一旦觸發限流,可以采取不同的處理策略,如拒絕請求、延遲處理、返回錯誤信息等。具體的限流策略可以根據實際情況進行選擇。

通過滑動日志算法進行限流,可以實現對單位時間內的請求進行精確控制。它基于實時統計的方式,能夠動態地適應請求流量的變化,并且在內存使用上比較高效。同時,通過調整時間窗口的長度和閾值的設置,可以靈活地控制限流的精度和靈敏度。

import java.util.LinkedList;
import java.util.List;
public class SlidingLogRateLimiter {private int requests; // 請求總數private List<Long> timestamps; // 存儲請求的時間戳列表private long windowDuration; // 窗口持續時間,單位:毫秒private int threshold; // 窗口內的請求數閥值public SlidingLogRateLimiter(int threshold, long windowDuration) {this.requests = 0;this.timestamps = new LinkedList<>();this.windowDuration = windowDuration;this.threshold = threshold;    }public synchronized boolean tryAcquire() {long currentTime = System.currentTimeMillis(); // 獲取當前時間戳// 刪除超過窗口持續時間的時間戳while (!timestamps.isEmpty() && currentTime - timestamps.get(0) > windowDuration) {timestamps.remove(0);requests--;}if (requests < threshold) { // 判斷當前窗口內請求數是否小于閥值timestamps.add(currentTime); // 將當前時間戳添加到列表requests++; // 請求總數增加return true; // 獲取請求成功}return false; // 超過閥值,無法獲取請求}
}

代碼解讀:

在以上代碼中,requests表示請求總數,timestamps用于存儲請求的時間戳列表,windowDuration表示窗口持續時間,threshold表示窗口內的請求數閥值。

在構造函數中傳入窗口內的請求數閥值和窗口持續時間。

tryAcquire()方法使用了synchronized關鍵字來實現線程安全,在方法中進行以下操作:

  1. 獲取當前系統時間戳 currentTime。
  2. 刪除超過窗口持續時間的時間戳,同時更新請求總數。
  3. 判斷當前窗口內請求數是否小于閥值。

如果小于閥值,將當前時間戳添加到列表,請求總數增加,并返回true表示獲取請求成功。如果已經達到或超過閥值,表示請求數已滿,返回false表示無法獲取請求。

使用這個滑動日志限流算法,可以限制在一定時間窗口內的請求頻率,超過閥值的請求會被限制。您可以根據實際需求和業務場景進行調整和使用。

適用場景

優勢

  • 滑動日志能夠避免突發流量,實現較為精準的限流;
  • 更加靈活,能夠支持更加復雜的限流策略 如多級限流,每分鐘不超過100次,每小時不超過300次,每天不超過1000次,我們只需要保存最近24小時所有的請求日志即可實現。

劣勢

  • 占用存儲空間要高于其他限流算法。

三、常用工具

3.1?RateLimiter(單機)

基于令牌桶算法實現的一個多線程限流器,它可以將請求均勻的進行處理,當然他并不是一個分布式限流器,只是對單機進行限流。它可以應用在定時拉取接口數。通過aop、filter、Interceptor 等都可以達到限流效果。

用法

以下是一個基本的 RateLimiter 用法示例:

import com.google.common.util.concurrent.RateLimiter;
public class RateLimiterDemo {public static void main(String[] args) {// 創建一個每秒允許2個請求的RateLimiterRateLimiter rateLimiter = RateLimiter.create(2.0);while (true) {// 請求RateLimiter一個令牌rateLimiter.acquire();// 執行操作doSomeLimitedOperation();}}private static void doSomeLimitedOperation() {// 模擬一些操作System.out.println("Operation executed at: " + System.currentTimeMillis());}
}

在這個例子中,RateLimiter.create(2.0) 創建了一個每秒鐘只允許2個操作的限速器。rateLimiter.acquire() 方法會阻塞當前線程直到獲取到許可,確保調用 doSomeLimitedOperation() 操作的頻率不會超過限制。

RateLimiter 還提供了其他的方法,例如tryAcquire(),它會嘗試獲取許可而不會阻塞,立即返回獲取成功或失敗的結果。還可以設置等待時間上限,比如 tryAcquire(long timeout, TimeUnit unit) 可以設置最大等待時間。

Guava的RateLimiter非常靈活,它支持平滑突發限制(SmoothBursty)和平滑預熱限制(SmoothWarmingUp)等多種模式,可以根據特定的應用場景來選擇合適的限流策略。

3.2?sentinel(單機或者分布式)

Sentinel是阿里巴巴開源的一款面向分布式系統的流量控制和熔斷降級組件。它提供了實時的流量控制、熔斷降級、系統負載保護和實時監控等功能,可以幫助開發者保護系統的穩定性和可靠性。

單機模式

  • DefaultController:是一個非常典型的滑動窗口計數器算法實現,將當前統計的qps和請求進來的qps進行求和,小于限流值則通過,大于則計算一個等待時間,稍后再試;
  • ThrottlingController:是漏斗算法的實現,實現思路已經在源碼片段中加了備注;
  • WarmUpController:實現參考了Guava的帶預熱的RateLimiter,區別是Guava側重于請求間隔,類似前面提到的令牌桶,而Sentinel更關注于請求數,和令牌桶算法有點類似;
  • WarmUpRateLimiterController:低水位使用預熱算法,高水位使用滑動窗口計數器算法排隊。

集群模式

Sentinel 集群限流服務端有兩種啟動方式:

  • 嵌入模式(Embedded)適合應用級別的限流,部署簡單,但對應用性能有影響
  • 獨立模式(Alone)適合全局限流,需要獨立部署

用法

Sentinel的用法主要包括以下幾個方面:

(1)引入依賴:在項目中引入Sentinel的相關依賴,可以使用Maven或Gradle進行依賴管理。例如,在Maven項目的pom.xml文件中添加以下依賴:

<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-core</artifactId><version>1.8.2</version>
</dependency>

(2)配置規則:根據實際需求,配置Sentinel的流量控制規則、熔斷降級規則等。可以通過編程方式或配置文件方式進行規則的配置。例如,可以在啟動類中使用注解方式配置流量控制規則:

@SentinelResource(value = "demo", blockHandler = "handleBlock")
public String demo() {// ...
}

(3)啟動Agent:在應用啟動時,啟動Sentinel的Agent,開啟對系統的流量控制和熔斷降級功能的保護。可以通過命令行啟動Agent,或者在代碼中進行啟動。例如,在Spring Boot的啟動類中添加如下代碼:

public static void main(String[] args) {System.setProperty("csp.sentinel.dashboard.server", "localhost:8080"); // 設置控制臺地址System.setProperty("project.name", "your-project-name"); // 設置應用名稱com.alibaba.csp.sentinel.init.InitExecutor.doInit();SpringApplication.run(YourApplication.class, args);
}

(4)監控和管理:使用Sentinel的控制臺進行實時監控、配置管理等操作。可以通過瀏覽器訪問Sentinel的控制臺界面,查看系統的運行情況和流量控制情況。通過控制臺,可以對規則進行動態修改,查看監控數據和告警信息。

3.3 Nginx(分布式)

Nginx從網關這一層面考慮,可以作為最前置的網關,抵擋大部分的網絡流量,因此使用Nginx進行限流也是一個很好的選擇,在Nginx中,也提供了常用的基于限流相關的策略配置。

用法

Nginx 提供了兩種限流方法:一種是控制速率,另一種是控制并發連接數。

控制速率

我們需要使用 limit_req_zone 用來限制單位時間內的請求數,即速率限制,因為Nginx的限流統計是基于毫秒的,我們設置的速度是 2r/s,轉換一下就是500毫秒內單個IP只允許通過1個請求,從501ms開始才允許通過第2個請求。

控制速率優化版

上面的速率控制雖然很精準但是在生產環境未免太苛刻了,實際情況下我們應該控制一個IP單位總時間內的總訪問次數,而不是像上面那樣精確到毫秒,我們可以使用 burst 關鍵字開啟此設置。

burst=4意思是每個IP最多允許4個突發請求

控制并發數

利用 limit_conn_zone 和 limit_conn 兩個指令即可控制并發數

其中 limit_conn perip 10 表示限制單個 IP 同時最多能持有 10 個連接;limit_conn perserver 100 表示 server 同時能處理并發連接的總數為 100 個。

注意:只有當 request header 被后端處理后,這個連接才進行計數。

四、小結

算法簡介核心思想優點

缺點

開源工具/中間件適用業務場景
固定窗口限流在固定的時間窗口內計數請求,達到閾值則限流。將時間分割成固定大小的窗口,每個窗口內獨立計數。實現簡單,性能較好。可能會有時間窗口切換時的突發流量。Nginx、Apache、RateLimiter (Guava)

需要簡單限流,對流量突增不敏感的場景。

eg:

電商平臺在每日定時秒殺活動開始時,用于防止瞬時高流量沖垮系統。

滑動窗口限流在滑動的時間窗口內計數請求,達到閾值則限流。將時間分割為多個小窗口,統計近期內的總請求數。平滑請求,避免固定窗口算法中的突發流量。實現比固定窗口復雜,消耗資源較多。Redis、Sentinel

對流量平滑性有較高要求的場景。



eg:

社交媒體平臺的消息發送功能,用于平滑處理高峰期的消息發送請求,避免服務短暫的超負荷。

令牌桶限流以恒定速率向桶中添加令牌,請求消耗令牌,無令牌時限流。以一定速率生成令牌,請求必須擁有令牌才能執行。允許一定程度的突發流量,平滑處理請求。對突發流量的容忍可能導致短時間內資源過載。

Guava、Nginx、Apache、

Sentinel

對突發流量有一定要求,且需要一定程度的平滑處理的場景。



eg:

視頻流媒體服務,允許用戶在網絡狀況良好時快速緩沖視頻,同時在網絡擁堵時平滑地降低請求速率。

漏桶算法漏桶以固定速率出水,請求以任意速率流入桶內,桶滿則溢出(限流)。以恒定的速率處理請求,超過該速率的請求被限制。輸出流量穩定,能夠限制流量的最大速率。無法應對突發流量,可能導致請求等待時間過長。Apache、Nginx

適用于需要嚴格控制處理速率,對請求響應時間要求不高的場景。



eg:

API網關對外提供服務的接口,需要確保后端服務的調用速率不超過其最大處理能力,防止服務崩潰

滑動日志限流使用滑動時間窗口記錄請求日志,通過日志來判斷是否超出速率限制。記錄最近一段時間內的請求日志,實時判斷請求是否超限。能夠更細粒度地控制請求速率,比固定窗口更公平。實現復雜,存儲和計算請求日志成本較高。-

對實時性要求高,且需要精確控制請求速率的高級限流場景。



eg:

高頻交易系統,需要根據實時交易數據精確控制交易請求速率,防止因超負荷而影響整體市場的穩定性。

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

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

相關文章

視頻監控聯網系統GB28181協議中設備控制流程詳解

文章目錄 9.3 設備控制9.3.1 基本要求9.3.2 命令流程9.3.2.1 無應答命令流程 9.3.3 協議接口9.3.3.1 請求命令9.3.3.2 應答命令 智聯視頻超融合平臺介紹 9.3 設備控制 9.3.1 基本要求 控制滿足以下基本要求&#xff1a; a) 源設備向目標設備發送控制命令&#xff0c;控制命令…

深入剖析原型模式:原理、實現與應用實踐

在軟件開發的世界里,設計模式如同建筑師手中的藍圖,為復雜系統的構建提供了行之有效的解決方案。其中,原型模式(Prototype Pattern)作為創建型設計模式的重要一員,以其獨特的對象創建方式,在提高代碼復用性、增強系統靈活性等方面發揮著關鍵作用。本文將深入剖析原型模式…

圖繪Linux:基礎指令脈絡閣

目錄 Linux命令行介紹 目錄操作 ls 目錄所含文件信息 ls 常用選項 pwd 在那個目錄下 cd 進入目錄 mkdir 創建目錄 文件操作 touch 創建普通文件 echo向文件寫入 cat 輸出文件內容 cp 拷貝文件/目錄 mv剪切重命名 rm 刪除文件/目錄 查找 * 匹配符 man 查找指令 …

數據分析 —— 數據預處理

一、什么是數據預處理 數據預處理&#xff08;Data Preprocessing&#xff09;是數據分析和機器學習中至關重要的步驟&#xff0c;旨在將原始數據轉換為更高質量、更適合分析或建模的形式。由于真實世界的數據通常存在不完整、不一致、噪聲或冗余等問題&#xff0c;預處理可以…

【Redis】哨兵(Sentinel)機制

文章目錄 1. Redis Sentinel的概念1.1 基本概念1.2 引出高可用 2. Redis Sentinel的部署&#xff08;基于docker&#xff09;2.1 部署2.2 驗證2.3 選舉流程 Redis 的主從復制模式下&#xff0c;?旦主節點由于故障不能提供服務&#xff0c;需要人工進行主從切換&#xff0c;同時…

初識Linux · 五種IO模型和非阻塞IO

目錄 前言&#xff1a; 五種IO模型 什么是IO IO模型 非阻塞IO 前言&#xff1a; 前文我們已經將網絡的基本原理介紹完了&#xff0c;都是通過圍繞TCP/IP四層協議&#xff0c;將應用層&#xff0c;傳輸層&#xff0c;網絡層&#xff0c;數據鏈路層全部介紹完畢&#xff0c…

Node.js 24發布:性能與安全雙提升

在科技的迅速發展中&#xff0c;Node.js作為一個備受青睞的開源跨平臺Java運行環境&#xff0c;近日迎來了其24.0版本的正式發布。此次更新不僅承諾提升性能和安全性&#xff0c;還為開發者提供了更為順暢的開發體驗&#xff0c;值得我們深入探討。 Node.js 24.0的最大亮點之一…

SLAM文獻之-SuperOdometry: Lightweight LiDAR-inertial Odometry and Mapping

《Super Odometry: IMU-centric LiDAR-Visual-Inertial Estimator for Challenging Environments》是一篇旨在增強 SLAM 系統在惡劣環境下魯棒性的工作&#xff0c;尤其關注塵霧、煙霧等遮擋條件下的魯棒估計。下面從算法原理、公式推導、創新點和應用場景四個方面進行詳細解析…

指令燒錄ORIN NANO操作系統

1 概述 模組為ORIN NANO 4GB版本 Ubuntu系統為18.04虛擬機 說明&#xff1a;刷機過程會有重新連接USB的操作&#xff0c;燒寫過程需要注意虛擬機提示&#xff0c;官方不建議使用虛擬機&#xff0c;建議直接使用ubuntu操作系統的機器。 2 下載燒錄所需文件 進入到下載網址&am…

游戲引擎學習第287天:加入brain邏輯

Blackboard&#xff1a;動態控制類似蛇的多節實體 我們目前正在處理一個關于實體系統如何以組合方式進行管理的問題。具體來說&#xff0c;是在游戲中實現多個實體可以共同或獨立行動的機制。例如&#xff0c;我們的主角擁有兩個實體組成部分&#xff0c;一個是身體&#xff0…

QML定時器Timer和線程任務WorkerScript

定時器 Timer 屬性 interval: 事件間隔毫秒repeat: 多次執行&#xff0c;默認只執行一次running: 定時器啟動triggeredOnStart: 定時器啟動時立刻觸發一次事件 信號 triggered(): 定時時間到&#xff0c;觸發此信號 方法 restart(): 重啟定時器start(): 啟動定時器stop(): 停止…

Linux中的域名解析服務器

一、DNS&#xff08;域名系統&#xff09;詳解 1. 核心功能與特點 特性說明核心作用將域名&#xff08;如 www.example.com&#xff09;轉換為 IP 地址&#xff08;如 192.168.1.1&#xff09;&#xff0c;實現人類可讀地址與機器可讀地址的映射。端口與協議- 默認端口&#…

Springboot2

1、搭建環境 2、配置文件 application.properties application.yml 3、springboot接收請求 springspringmvc 接收請求 響應數據 4、springboot集成jdbc spring-boot-starter-jdbc.jar JdbcTemplate(update|query) 5、springboot自動裝配原理&#xff08;重點&#x…

【課堂筆記】核方法和Mercer定理

文章目錄 Kernal引入定義Mercer定理描述有限情形證明一般情形證明 Kernal 引入 在實際數據中常常遇到不可線性分割的情況&#xff0c;此時通常需要將其映射到高維空間中&#xff0c;使其變得線性可分。例如二維數據&#xff1a; 通過映射 ? ( x 1 , x 2 ) ( x 1 2 , 2 x 1…

談談未來iOS越獄或巨魔是否會消失

2024年10月的預測&#xff0c;先說結論&#xff1a; 巨魔iOS17.1消失概率為99%。 因為巨魔強依賴的漏洞就是一個簽名漏洞&#xff0c;攻擊面有限又經過2輪修復&#xff0c;第3次出現漏洞的概率極低。而越獄的話由于系統組件和服務較多&#xff0c;所以出現漏洞概率高攻擊面多&…

根據當前日期計算并選取上一個月和上一個季度的日期范圍,用于日期控件的快捷選取功能

1.選擇月份范圍 代碼如下&#xff1a; <el-date-picker v-model"value" type"monthrange" align"right" unlink-panels range-separator"至"start-placeholder"開始月份" end-placeholder"結束月份" :picker-…

用戶棧的高效解析邏輯

一、背景 在之前的博客 內核邏輯里抓取用戶棧的幾種方法-CSDN博客 里&#xff0c;介紹了使用內核邏輯進行用戶棧的函數地址的抓取邏輯&#xff0c;但是并沒有涉及如何解析出函數符號的邏輯。 就如perf工具一樣&#xff0c;它也是分為兩個步驟&#xff0c;一個步驟是內核態抓取…

vue3 el-table 行號

在 Vue 3 中&#xff0c;使用 Element Plus 的 <el-table> 組件來創建表格時&#xff0c;如果你想添加行號&#xff08;即每一行的編號&#xff09;&#xff0c;可以通過自定義列來實現。下面是如何實現的步驟&#xff1a; 1. 安裝 Element Plus 首先&#xff0c;確保你…

Linux:進程信號---信號的保存與處理

文章目錄 1. 信號的保存1.1 信號的狀態管理 2. 信號的處理2.1 用戶態與內核態2.2 信號處理和捕捉的內核原理2.3 sigaction函數 3. 可重入函數4. Volatile5. SIGCHLD信號 序&#xff1a;在上一章中&#xff0c;我們對信號的概念及其識別的底層原理有了一定認識&#xff0c;也知道…

UML 圖的細分類別及其應用

統一建模語言&#xff08;UML&#xff0c;Unified Modeling Language&#xff09;是一種用于軟件系統建模的標準化語言&#xff0c;廣泛應用于軟件工程領域。UML 圖分為多種類別&#xff0c;每種圖都有其特定的用途和特點。本文將詳細介紹 UML 圖的細分類別&#xff0c;包括 類…