基于分布式環境的令牌桶與漏桶限流算法對比與實踐指南

基于分布式環境的令牌桶與漏桶限流算法對比與實踐指南

在高并發的分布式系統中,限流是保障服務可用性和穩定性的核心手段。本文聚焦于令牌桶算法漏桶算法在分布式環境下的實現與優化,對多種解決方案進行橫向對比,分析各自的優缺點,并給出選型建議與實際應用案例,附帶完整可運行的代碼示例和配置方案,幫助后端開發者在生產環境中快速落地。

1. 問題背景介紹

隨著微服務架構和云原生模式的普及,API 調用和消息處理的并發請求量與日俱增。一旦流量突增,若沒有有效的限流策略,后端依賴的數據庫、緩存或下游服務將出現過載,甚至導致整體服務不可用。

在單機場景下,基于內存的令牌桶和漏桶算法即可滿足大多數需求;但在分布式部署時,需要依托外部存儲(如 Redis)或集群組件,實現多節點下的全局限流。

核心需求

  • 全局限流:多個實例共同限流,保證調用速率上限。
  • 可配置性:根據業務場景,靈活調整最大吞吐量和突發容量。
  • 高可用與容錯:限流組件自身需具備高可用特性,不為單點所累。
  • 性能開銷可控:限流操作的延遲需足夠低,以免影響請求響應。

2. 多種解決方案對比

針對分布式環境的限制需求,主要有以下幾種方案:

方案一:基于 Redis 的分布式令牌桶
方案二:基于 Redis 的分布式漏桶
方案三:基于 Guava RateLimiter + 本地冷啟動 + 一致性哈希(混合模式)

| 方案 | 原理 | 存儲中心 | 線程安全 | 突發支持 | 關鍵點 | | ---- | ---- | ---- | ---- | ---- | ---- | | Redis 令牌桶 | 令牌以固定速率注入桶中,業務取令牌才能執行。| Redis list / zset | Lua 腳本原子操作 | 支持桶容量 | 腳本原子性、隊列裁剪 | | Redis 漏桶 | 請求進入漏桶隊列,以固定速率流出,超出緩沖區則拒絕。| Redis list | Lua 腳本原子操作| 不支持突發(等同固定速率) | 控制隊列長度 | | 本地 RateLimiter 混合 | 本地先處理一定量請求,超出后再分布式請求令牌 | Guava + Redis | Guava + Redis 腳本 | 支持本地突發,遠程限流 | 本地熱點均衡、一致性哈希 |

3. 各方案優缺點分析

3.1 方案一:Redis 分布式令牌桶

優點:

  • 支持突發流量,令牌可積累。
  • 原理成熟,社區實踐多。

缺點:

  • 依賴 Redis 性能,Lua 腳本壓力大時可能成為瓶頸。
  • 桶容量需合理設置,否則可能過度放行短時突發。

3.2 方案二:Redis 分布式漏桶

優點:

  • 出流速率恒定,業務峰值可被平滑化。
  • 實現簡單,配置漏出速率即可。

缺點:

  • 不支持突發流量處理,突發請求將被拒絕。
  • 隊列長度限定下,易出現丟棄。

3.3 方案三:本地 RateLimiter + 混合模式

優點:

  • 本地優先限流,降低遠程調用頻率。
  • 支持本地突發與全局平滑。

缺點:

  • 實現復雜,需要解決本地與全局令牌同步問題。
  • 一致性哈希或熱點 imbalanced 帶來挑戰。

4. 選型建議與適用場景

  • 高突發場景:建議使用Redis 令牌桶,可設定足夠容量的令牌桶,應對短時流量峰值;
  • 流量平穩場景:建議使用Redis 漏桶,平滑輸出,降低下游波動;
  • 混合流量場景:對延遲敏感且需承受突發,建議本地 RateLimiter + 遠程混合,兼顧性能與全局限流。

5. 實際應用效果驗證

以下示例以 Spring Boot + Redis 為例:

項目結構:

rate-limit-demo/
├── src/main/java/com/example/ratelimit/
│   ├── config/RedisConfig.java
│   ├── limiter/RedisTokenBucketLimiter.java
│   ├── limiter/RedisLeakyBucketLimiter.java
│   └── controller/TestController.java
└── src/main/resources/application.yml

5.1 Redis 配置 (application.yml)

spring:redis:host: localhostport: 6379database: 0

5.2 Lua 腳本(token_bucket.lua

local key = KEYS[1]
local now = tonumber(ARGV[1])
local rate = tonumber(ARGV[2])
local capacity = tonumber(ARGV[3])--獲取當前桶狀態
dir = redis.call('hmget', key, 'tokens', 'timestamp')
tokens = tonumber(dir[1])
timestamp = tonumber(dir[2])
if not tokens then tokens = capacity end
if not timestamp then timestamp = now end--計算新令牌數
delta = math.max(0, now - timestamp) * rate
tokens = math.min(capacity, tokens + delta)
if tokens < 1 thenreturn 0
elsetokens = tokens - 1redis.call('hmset', key, 'tokens', tokens, 'timestamp', now)return 1
end

5.3 Java 實現示例

@Service
public class RedisTokenBucketLimiter {private final String LUA_SCRIPT = "...token_bucket.lua內容...";private final int capacity = 100;private final double rate = 10.0; //9條/秒private final RedisScript<Long> script;@Autowiredprivate StringRedisTemplate redisTemplate;public RedisTokenBucketLimiter() {this.script = new DefaultRedisScript<>(LUA_SCRIPT, Long.class);}public boolean tryAcquire(String key) {long now = System.currentTimeMillis() / 1000;Long result = redisTemplate.execute(script,Collections.singletonList(key),String.valueOf(now), String.valueOf(rate), String.valueOf(capacity));return result != null && result == 1;}
}

在 Controller 中調用:

@RestController
public class TestController {@Autowiredprivate RedisTokenBucketLimiter limiter;@GetMapping("/api/test")public ResponseEntity<String> test() {if (!limiter.tryAcquire("api_test_bucket")) {return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body("限流了,請稍后再試");}return ResponseEntity.ok("請求成功");}
}

5.4 性能與效果驗證

在壓測工具(如 JMeter)下,模擬 200 并發請求:

  • 令牌桶模式下,短時內可觸發突發(最多 100 請求)。
  • 漏桶模式下,持續穩定輸出,保證 QPS 恒定在設定流速。
  • 混合模式下,本地快速響應 + 全局限流,延遲更低,集群容量更優。

以上即基于分布式環境中令牌桶與漏桶算法的詳細對比與實踐指南,希望能幫助您在實際項目中高效、可靠地實現限流。

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

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

相關文章

WPF MVVM入門系列教程(TabControl綁定到列表并單獨指定每一頁內容)

在以前的開發過程中&#xff0c;對于TabControl控件&#xff0c;我一般是習慣直接定義TabItem&#xff0c;在TabItem下布局&#xff0c;并進行綁定。 類似這樣 1 <TabControl ItemsSource"{Binding TabList}" SelectedIndex"0">2 <TabItem…

L2CAP 面向連接信道(CoC)在 BLE 中的應用:建立、流控與數據傳輸

在物聯網(IoT)蓬勃發展的今天,低功耗藍牙(BLE)技術因其高效節能、低成本等特性,成為短距離無線通信的首選方案。作為 BLE 協議棧的核心組件,邏輯鏈路控制與適配協議(L2CAP)的面向連接信道(CoC)承擔著數據傳輸的關鍵任務。本文將深入解析 L2CAP CoC 在 BLE 中的應用,…

醫療AI與醫院數據倉庫的智能化升級:異構采集、精準評估與高效交互的融合方向(上)

摘要: 隨著醫療信息化建設的深入,醫院數據倉庫(Data Warehouse, DW)作為醫療AI應用的核心數據底座,其效能直接決定智能化轉型的深度與廣度。本文聚焦醫療AI驅動下醫院數據倉庫的三大關鍵升級功能——異構采集支持數據庫體檢與智能SQL分析、評估引擎重構實現六大數據庫精準…

2015-2018年咸海流域1km歸一化植被指數8天合成數據集

數據集摘要數據集包含2015年-2018年咸海流域NDVI 8天均值數據。提取美國國家航空航天局中分辨率成像光譜儀MOD13A2產品第一波段作為歸一化植被指數數據&#xff0c;乘以比例因子0.0001&#xff0c;疊加咸海流域邊界數據&#xff0c;裁切后得到咸海流域范圍內的NDVI月均值數據。…

Kafka消息持久化機制全解析:存儲原理與實戰場景

目錄 引言? 一、Kafka消息持久化的核心目標 二、底層存儲機制深度剖析 1.【文件系統分層】——日志分組 日志段 核心結構 示例目錄結構 2.【消息寫入流程】——從內存到磁盤的旅程?? 3.【默認存儲參數】——生產環境的黃金比例 三、典型應用場景與案例實戰 案例1…

Python訓練營打卡Day41-Grad-CAM與Hook函數

知識點回顧回調函數lambda函數hook函數的模塊鉤子和張量鉤子Grad-CAM的示例 作業&#xff1a;理解下今天的代碼即可 在深度學習中&#xff0c;我們經常需要查看或修改模型中間層的輸出或梯度。然而&#xff0c;標準的前向傳播和反向傳播過程通常是一個黑盒&#xff0c;我們很難…

使用VBA宏批量修改Word中表格題注格式

目錄&#x1f4c2; 使用步驟? 方式一&#xff1a;應用已有樣式&#xff08;推薦&#xff09;代碼實現說明? 方式二&#xff1a;手動設置字體格式&#xff08;無需預定義樣式&#xff09;代碼實現參數說明如何運行宏&#xff1f;補充建議總結在撰寫論文、技術文檔或報告時&…

Redis面試精講 Day 27:Redis 7.0/8.0新特性深度解析

【Redis面試精講 Day 27】Redis 7.0/8.0新特性深度解析 在“Redis面試精講”系列的第27天&#xff0c;我們將聚焦Redis最新版本——7.0與8.0的核心新特性。隨著Redis從內存數據庫向云原生、高可用、高性能中間件持續演進&#xff0c;7.0和8.0版本引入了多項顛覆性改進&#xf…

使用自制的NTC測量模塊測試Plecs的熱仿真效果

之前構建的 NTC 溫度測量模型是進行 PLECS 熱仿真的完美起點和核心組成部分。 PLECS 的強大之處在于它能夠進行多域仿真,特別是電-熱聯合仿真。您可以將電路仿真(包括您的 NTC 測量模型)與熱仿真(散熱器、熱容、熱阻等)無縫地結合起來。 電-熱聯合仿真原理 整個仿真閉環…

C語言初學者筆記【動態內存管理】

、 文章目錄一、為什么需要動態內存分配&#xff1f;二、malloc 和 free1. malloc2. free三、calloc 和 realloc1. calloc2. realloc四、常見的動態內存錯誤1. 對 NULL 解引用2. 越界訪問3. 對非動態內存使用 free4. 釋放部分動態內存5. 多次釋放同一塊內存6. 內存泄漏五、動態…

AI模型部署 - 大語言模型(LLM)部署技術與框架

目錄 一、 大語言模型部署的核心挑戰與關鍵技術 二、 主流開源部署框架深度解析 2.1. Ollama:本地部署的極簡主義者 2.2. Hugging Face TGI (Text Generation Inference) 2.3. vLLM:為吞吐量而生 2.4. sglang:面向復雜提示與結構化輸出的革新者 三、 特定硬件與云平臺…

Windows11 GeForce GTX 1060 CUDA+CUDNN+Pytorch 下載及安裝

一、查看顯卡型號信息 系統&#xff1a;Windows11 顯卡&#xff1a;GeForce GTX 1060 型號&#xff1a; &#xff08;1&#xff09;搜索 NVIDIA&#xff0c;選擇 NVIDIA Control Panel&#xff08;2&#xff09;打開 NVIDIA control Panel&#xff0c;打開系統信息&#xff0c;…

在通義靈碼中配置MCP服務

目錄 查找mcp列表 通義靈碼中配置MCP 使用方式 STDIO (Standard Input/Output) 組成部分&#xff1a; SSE (Server-Sent Events) 特點&#xff1a; 主要區別對比 配置方式 配置優先級 個人設置 項目設置 驗證 通過MCP調用高德地圖 查找mcp列表 打開ModelScope - …

網絡中的IO問題(五種常見的IO方式)

什么是高效的IO&#xff1f; 正常情況下&#xff0c;IO等拷貝 高效的IO拷貝&#xff08;即讓IO盡量不等&#xff09; 為什么我們平常玩電腦的時候&#xff0c;感覺不到等待的過程呢&#xff1f; 任何通信場景&#xff0c;IO通信場景&#xff0c;效率一定是有上限的. 花盆里&am…

JAVA核心基礎篇-修飾符

Java 修飾符主要用于定義類、方法或變量&#xff0c;通常放在語句的最前端&#xff0c;可分為訪問修飾符和非訪問修飾符兩類。一、訪問修飾符public&#xff1a;對所有類可見&#xff0c;可用于類、接口、變量和方法。被聲明為 public 的類、方法、構造方法和接口能夠被任何其他…

筆試——Day46

文章目錄第一題題目思路代碼第二題題目思路代碼第三題題目思路代碼第一題 題目 AOE還是單體&#xff1f; 思路 貪心 剩余怪物數量 >x時&#xff0c;使用AOE&#xff1b;否則使用單體 代碼 #include <iostream> #include <algorithm> using namespace std;…

零工合規挑戰:蓋雅以智能安全體系重構企業用工風控

國家稅務總局發布的2025年第15號公告&#xff0c;將多種互聯網平臺企業納入涉稅信息報送范圍&#xff0c;這讓靈活用工平臺的數據和網絡安全問題成為行業關注的焦點。在海量零工信息和企業數據流轉的過程中&#xff0c;數據泄露和網絡攻擊的風險不斷上升&#xff0c;迫使平臺在…

非線性規劃學習筆記

非線性規劃學習筆記 一、非線性規劃的應用 非線性規劃&#xff08;Nonlinear Programming, NLP&#xff09;在很多領域都有重要應用&#xff0c;主要包括&#xff1a; 工程設計優化&#xff1a;結構優化、電路參數優化、交通線路設計經濟與管理&#xff1a;投資組合優化、生產計…

網絡模型深度解析:CNI、Pod通信與NetworkPolicy

目錄 專欄介紹 作者與平臺 您將學到什么&#xff1f; 學習特色 網絡模型深度解析&#xff1a;CNI、Pod通信與NetworkPolicy 第一部分&#xff1a;CNI 插件原理 - 網絡基礎設施的構建者 1.1 CNI 規范&#xff1a;標準化網絡接入的基石 1.2 Flannel&#xff1a;簡單高效的…

數據結構青銅到王者第二話---數據結構基本常識(2)

續接上一話 一、包裝類 在Java中&#xff0c;由于基本類型不是繼承自Object&#xff0c;為了在泛型代碼中可以支持基本類型&#xff0c;Java給每個基本類型都對應了一個包裝類型。 1、基本數據類型和對應的包裝類 除了 Integer 和 Character&#xff0c; 其余基本類型的包裝類…