【Golang面試題】Go語言實現請求頻率限制

Go語言實現請求頻率限制:從計數器到令牌桶的完整指南

在實際開發中,接口被惡意刷請求是常見問題。本文將深入探討Go語言中四種主流的請求限流方案,從簡單到復雜逐步深入,助你構建高可用服務。

一、基礎方案:計數器法(固定窗口)

適用場景:簡單業務、低并發需求


type CounterLimiter struct {mu       sync.Mutexcount    intinterval time.DurationmaxReq   intlastReset time.Time
}func NewCounterLimiter(interval time.Duration, maxReq int) *CounterLimiter {return &CounterLimiter{interval:  interval,maxReq:    maxReq,lastReset: time.Now(),}
}func (c *CounterLimiter) Allow() bool {c.mu.Lock()defer c.mu.Unlock()// 檢查是否需要重置計數器if time.Since(c.lastReset) > c.interval {c.count = 0c.lastReset = time.Now()}// 檢查是否超過限制if c.count >= c.maxReq {return false}c.count++return true
}// HTTP中間件示例
func RateLimitMiddleware(limiter *CounterLimiter) func(http.Handler) http.Handler {return func(next http.Handler) http.Handler {return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {if !limiter.Allow() {w.Header().Set("Retry-After", "60")http.Error(w, "Too Many Requests", http.StatusTooManyRequests)return}next.ServeHTTP(w, r)})}
}

優點

  • 實現簡單,內存占用低
  • 無第三方依賴

缺點

  • 窗口邊界突發流量問題
  • 分布式場景不適用

二、進階方案:Redis滑動窗口

適用場景:分布式系統、精確限流

const luaScript = `
local key = KEYS[1]
local now = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local max = tonumber(ARGV[3])redis.call('ZREMRANGEBYSCORE', key, 0, now - window)
local current = redis.call('ZCARD', key)if current >= max thenreturn 0
endredis.call('ZADD', key, now, now)
redis.call('EXPIRE', key, math.ceil(window/1000))
return 1
`type RedisLimiter struct {client   *redis.Clientscript   *redis.ScriptmaxReq   intwindow   time.Duration
}func NewRedisLimiter(client *redis.Client, window time.Duration, maxReq int) *RedisLimiter {return &RedisLimiter{client: client,script: redis.NewScript(luaScript),maxReq: maxReq,window: window,}
}func (r *RedisLimiter) Allow(userID string) bool {ctx := context.Background()key := fmt.Sprintf("rate_limit:%s", userID)now := time.Now().UnixMilli()result, err := r.script.Run(ctx, r.client, []string{key}, now, r.window.Milliseconds(), r.maxReq).Int()return err == nil && result == 1
}

實現要點

  1. 使用Redis有序集合存儲時間戳
  2. Lua腳本保證原子操作
  3. 自動清理過期請求
  4. 精確統計時間窗口內請求

優勢

  • 精確的滑動窗口計數
  • 分布式系統通用
  • 自動處理數據過期

三、高級方案:令牌桶算法

適用場景:允許突發流量、精細控制

type TokenBucket struct {capacity    int           // 桶容量tokens      int           // 當前令牌數fillRate    time.Duration // 添加令牌間隔lastRefill  time.Time     // 上次添加時間mu          sync.Mutex
}func NewTokenBucket(capacity int, rate time.Duration) *TokenBucket {return &TokenBucket{capacity:   capacity,tokens:     capacity,fillRate:   rate,lastRefill: time.Now(),}
}func (b *TokenBucket) Allow() bool {b.mu.Lock()defer b.mu.Unlock()// 補充令牌now := time.Now()elapsed := now.Sub(b.lastRefill)newTokens := int(elapsed / b.fillRate)if newTokens > 0 {b.tokens += newTokensif b.tokens > b.capacity {b.tokens = b.capacity}b.lastRefill = now}// 檢查令牌是否足夠if b.tokens <= 0 {return false}b.tokens--return true
}

算法特點

  • 允許短時間內突發流量
  • 精確控制平均速率
  • 實現相對復雜

四、生產級方案:使用成熟中間件

推薦庫

  • Tollbooth
  • Uber-go/ratelimit

Tollbooth示例


func main() {r := chi.NewRouter()// 創建限流器:每分鐘1000次limiter := tollbooth.NewLimiter(1000/60.0, nil)limiter.SetIPLookups([]string{"X-Real-IP", "RemoteAddr", "X-Forwarded-For"})// 應用中間件r.Use(tollbooth_chi.LimitHandler(limiter))r.Get("/api/protected", func(w http.ResponseWriter, r *http.Request) {w.Write([]byte("Protected content"))})http.ListenAndServe(":8080", r)
}

五、方案選型指南

方案實現復雜度精準度突發處理分布式支持
計數器法★☆☆☆☆★★☆☆☆
Redis滑動窗口★★★☆☆★★★★★
令牌桶算法★★★★☆★★★★☆允許突發有限
限流中間件★☆☆☆☆★★★★☆可配置

六、最佳實踐

  1. 分層防御

    • 前端:按鈕防重復點擊
    • 網關:基礎IP限流
    • 業務層:用戶級精細控制
  2. 動態調整

    // 動態調整限流閾值
    func adjustLimitBasedOnSystemLoad() {load := getSystemLoad()if load > 0.8 {limiter.SetMaxRequests(500) // 高負載時降低閾值}
    }
    
  3. 熔斷機制

    // 使用hystrix實現熔斷
    hystrix.ConfigureCommand("my_api", hystrix.CommandConfig{Timeout:               1000,MaxConcurrentRequests: 100,ErrorPercentThreshold: 50,
    })
    
  4. 監控指標

    • 請求拒絕率
    • 系統負載
    • 限流閾值命中率
    • Redis內存/QPS

總結

在Go語言中實現請求限流需要根據實際場景選擇方案:

  • 單機簡單場景:計數器法
  • 分布式系統:Redis滑動窗口
  • 允許合理突發:令牌桶算法
  • 快速上線:成熟中間件

黃金法則:沒有最好的限流方案,只有最適合業務場景的方案。建議從簡單實現開始,隨著業務增長逐步升級限流策略,最終構建包含多層防御的完整限流體系。

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

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

相關文章

11Labs 增長負責人分享:企業級市場將從消費級或開發者切入丨Voice Agent 學習筆記

本文摘自 Founder Park AI 產品如何做增長&#xff0c;ElevenLabs的案例很值得學習。 專注于 AI 語音生成的獨角獸企業 ElevenLabs 可以說一直在高速增長。在今年 1 月完成 1.8 億美元 C 輪融資后&#xff0c;ElevenLabs 的估值突破 30 億&#xff0c;直指 33 億美元。2024 年…

Linux 命令:grep

概述 在Linux系統里&#xff0c;grep是一款十分實用的命令行工具&#xff0c;它主要用于在文件或者輸入流中搜索符合特定模式的文本。下面為你詳細介紹它的用法。資料已經分類整理好&#xff1a;https://pan.quark.cn/s/26d73f7dd8a7 基本語法 grep [選項] 搜索模式 [文件..…

Java八股文——MySQL「架構篇」

MySQL主從復制了解嗎 面試官您好&#xff0c;我了解MySQL的主從復制。它是構建高可用、高可擴展數據庫架構的核心基石。 1. 主從復制的核心原理與流程 整個主從復制的過程&#xff0c;就是一場圍繞 binlog&#xff08;二進制日志&#xff09; 的“接力賽”。這個過程主要可以…

ubuntu下python版本升級導致pyqt不能正常運行解決

最終解決方案 ubuntu下多python版本pyqt兼容性問題解決 python3.9 -m pip install --upgrade --force-reinstall --prefer-binary pyqt5)嘗試解決方案一(失敗) 系統默認python版本可以&#xff0c;其他版本不行 sudo apt install pyqt5-dev-tools嘗試解決方案二(失敗) 一直…

AIGC工具平臺-VideoRetalking音頻對口型數字人

唇形合成技術正逐漸成為AIGC內容生產領域的重要工具&#xff0c;能夠實現音視頻數據的高度融合。基于VideoRetalking模塊的可視化界面降低了技術門檻&#xff0c;使非技術背景的用戶也能便捷體驗唇形驅動數字人合成的流程。 本文重點解析該模塊的使用方式及開發流程&#xff0…

前端項目如何部署為https

如何為項目部署設置HTTPS 設置HTTPS是保護網站數據傳輸安全的重要步驟。以下是設置HTTPS的主要方法&#xff1a; 1. 獲取SSL/TLS證書 免費證書選項 Let’s Encrypt&#xff1a;最流行的免費證書頒發機構Cloudflare&#xff1a;提供免費SSL和CDN服務ZeroSSL&#xff1a;另一…

nginx 配置 系統升級頁面

默認80端口配置如下&#xff1a; server {listen 80; # 指定端口號server_name 192.168.2.96; # 替換為實際域名或IP# 全局重定向到升級頁面&#xff08;排除自身防循環&#xff09;if ($request_uri !~* "/upgrade.html") {return 307 /upgrade.html; # 臨時重定…

計算機基礎(一)——設計模式

一、設計模式 設計模式&#xff08;Design Patterns&#xff09;是軟件開發中反復出現問題的解決方案的通用描述。 它是經過總結、提煉的高效代碼結構和設計方案&#xff0c;幫助開發者寫出更靈活、可維護和可擴展的代碼。 優點注意點規范代碼結構&#xff0c;提高開發效率設…

Mac電腦 磁盤檢測和監控工具 DriveDx

DriveDx Mac 一款不監視驅動器的內置S.M.A.R.T.狀態的先進驅動器運行狀況診斷和監測工具。 還分析了所有驅動器健康密切相關的指標&#xff0c; SSD或硬盤驅動器故障&#xff08;像SSD磨損 /耐久性&#xff0c;壞扇區重新分配&#xff0c;離線壞道&#xff0c;未定扇形區&…

頻繁操作Json嵌套數據PostgreSQL配合JSON操作工具類+sql

文章目錄 1.工具類2.依賴3.sql 本文檔只是為了留檔方便以后工作運維&#xff0c;或者給同事分享文檔內容比較簡陋命令也不是特別全&#xff0c;不適合小白觀看&#xff0c;如有不懂可以私信&#xff0c;上班期間都是在得 背景&#xff1a;因為頻繁操作json嵌套數據 PostgreSQL得…

京東云 centos vim有操作混亂的問題

centos云服務器 安裝micro編輯器可以解決 yum install micro

限流系列之二:TDMQ CKafka 版限流方案詳解及最佳實踐

導語 在當今大數據和實時通信的時代&#xff0c;消息隊列在分布式系統中扮演著至關重要的角色。CKafka 作為一種高性能、高可靠的消息中間件&#xff0c;被廣泛應用于各種業務場景中。然而&#xff0c;隨著業務的增長和數據流量的增加&#xff0c;CKafka 在生產者和消費者以極…

消息隊列的基本概念

文章目錄 為什么需要消息隊列&#xff1f;&#x1f914;&#x1f3af; 核心價值&#x1f4cb; 使用場景 &#x1f3d7;? 架構層面的基本概念整體架構圖&#x1f4e6; 核心組件詳解1. Broker&#xff08;消息代理&#xff09;2. Topic&#xff08;主題&#xff09;3. Partition…

Shell腳本中和||語法解析

https://www.cnblogs.com/liuyuelinfighting/p/16377705.html 在 Shell 腳本中&#xff0c;&& 和 || 是邏輯操作符&#xff0c;用于根據前一個命令的退出狀態&#xff08;成功或失敗&#xff09;決定是否執行后續命令。這種語法稱為 命令鏈&#xff08;Command Chainin…

MySQL中的常見運算符

精選專欄鏈接 &#x1f517; MySQL技術筆記專欄Redis技術筆記專欄大模型搭建專欄Python學習筆記專欄深度學習算法專欄 歡迎訂閱&#xff0c;點贊&#xff0b;關注&#xff0c;每日精進1%&#xff0c;共攀技術高峰 更多內容持續更新中&#xff01;希望能給大家帶來幫助~ &…

高級IO技術詳解:阻塞/非阻塞IO、多路復用與內存映射

高級IO技術詳解&#xff1a;阻塞/非阻塞IO、多路復用與內存映射 關鍵詞&#xff1a;阻塞IO 非阻塞IO select/poll/epoll mmap 一、阻塞IO vs 非阻塞IO 類型行為特點設置方式阻塞IO- 讀空管道阻塞- 寫滿管道阻塞默認模式非阻塞IO- 讀空文件返回 -1&#xff0c;errnoEAGAIN- 寫滿…

【無標題】拓撲對偶框架的嚴格性補完與哲學突破

拓撲對偶框架的嚴格性補完與哲學突破&#xff1a; 一、數學嚴格性補完&#xff1a;同調類守恒的解決方案 1.1 負系數問題的幾何化修正 **問題本質**&#xff1a;當 $a_i$ 含負數時&#xff0c;曲率分配 $\kappa\frac{2\pi a_i}{A_{\text{max}}}$ 導致偽黎曼流形 **解決方案…

從0開始學習R語言--Day25--A/B測試 vs 多臂老虎機

通常在比較兩個不同的方案對數據的影響時&#xff0c;我們會各拿50%的數據去進行對照試驗&#xff0c;這樣觀測到的結果會最大程度地保留統計學上的特點。但實際上&#xff0c;并不是所有對比不同方案都要這樣做&#xff0c;一來&#xff0c;我們需要等到兩組實驗都完全結束后&…

功耗高?加密弱?愛普特APT32F1023H8S6單片機 2μA待機+AES硬件加密破局

愛普特APT32F1023H8S6單片機深度解析 1. 產品定位 APT32F1023H8S6 是愛普特半導體&#xff08;APT&#xff09;推出的 32位高性能單片機&#xff0c;基于 ARM Cortex-M0內核&#xff0c;主打 高集成度、低功耗、高性價比&#xff0c;面向消費電子、工業控制和物聯網領域。 2. …

【MFC】繪制自定義控件-顯示圖片(支持放大操作)

目錄 一、CDC類&#xff08;二級緩存&#xff09;二、計算視口三、放大操作代碼中初始化操作&#xff08;方便以后cv&#xff09; 一、CDC類&#xff08;二級緩存&#xff09; CDC類是設備上下文的核心類&#xff0c;它的作用是抽象化對圖形輸出設備&#xff08;像屏幕、打印機…