【Golang】用官方rate包構造簡單IP限流器

文章目錄

  • 使用 Go 實現基于 IP 地址的限流機制
      • 什么是 IP 限流?
    • 基于 `rate.Limiter` 實現 IP 限流
      • 1. 設計思路
      • 2. 代碼實現
      • 3. 限流中間件
      • 4. 在 Gin 中使用中間件
      • 代碼解釋

使用 Go 實現基于 IP 地址的限流機制

在高流量的服務中,限流是一個至關重要的環節。它不僅能防止服務因過多請求而崩潰,還能保證服務的公平性。在本篇文章中,我們將介紹如何利用 Go 語言中的 golang.org/x/time/rate 包實現一個基于 IP 地址的限流機制。

什么是 IP 限流?

IP 限流是指根據客戶端的 IP 地址,對每個 IP 地址發出的請求進行限制。這樣可以防止某個單獨的用戶或機器通過頻繁的請求耗盡服務器資源。

基于 rate.Limiter 實現 IP 限流

Go 語言的 golang.org/x/time/rate 包提供了一個非常實用的令牌桶限流算法,能夠輕松控制請求的速率。在本實現中,我們將基于客戶端 IP 地址,為每個 IP 地址創建一個獨立的限流器。

1. 設計思路

我們使用 map[string]*rate.Limiter 來存儲每個 IP 地址的限流器,并為每個 IP 地址設定一個令牌桶。我們還要為每個 IP 地址記錄最后一次請求的時間,并在一定時間(TTL)后清除過期的限流器。

2. 代碼實現

首先,我們創建一個 IPRateLimiter 結構體,該結構體維護了所有 IP 的限流器、過期時間以及并發安全的鎖。

package middlewareimport ("github.com/gin-gonic/gin""github.com/sirupsen/logrus""golang.org/x/time/rate""sync""time""git.nominee.com.cn/sectrainx/stx-common/pkg/response"
)// IPRateLimiter 定義了 IP 限流器
type IPRateLimiter struct {ips        map[string]*rate.Limiter // 存儲每個 IP 的限流器ipLastUsed map[string]time.Time     // 記錄每個 IP 地址最后一次使用的時間mu         *sync.RWMutex            // 確保并發安全r          rate.Limit               // 每秒生成令牌數b          int                      // 令牌桶容量ttl        time.Duration            // 限流器的過期時間
}// NewIPRateLimiter 創建一個新的 IP 限流器實例
func NewIPRateLimiter(r rate.Limit, b int, ttl time.Duration) *IPRateLimiter {i := &IPRateLimiter{ips:        make(map[string]*rate.Limiter),ipLastUsed: make(map[string]time.Time),mu:         &sync.RWMutex{},r:          r,b:          b,ttl:        ttl,}return i
}// AddIP 創建并添加一個新的 IP 限流器
func (i *IPRateLimiter) AddIP(ip string) *rate.Limiter {i.mu.Lock()defer i.mu.Unlock()limiter := rate.NewLimiter(i.r, i.b)i.ips[ip] = limiteri.ipLastUsed[ip] = time.Now()	// 設置 IP 的最后使用時間return limiter
}// GetLimiter 獲取指定 IP 地址的限流器
func (i *IPRateLimiter) GetLimiter(ip string) *rate.Limiter {i.mu.Lock()defer i.mu.Unlock()// 如果限流器存在,并且 IP 沒有過期,則返回現有的限流器if limiter, exists := i.ips[ip]; exists {if time.Since(i.ipLastUsed[ip]) < i.ttl {i.ipLastUsed[ip] = time.Now() // 更新最后訪問時間return limiter} else {// 如果限流器已經過期,刪除delete(i.ips, ip)delete(i.ipLastUsed, ip)}}// 不存在,創建新的限流器return i.AddIP(ip)
}// 定時清理過期的 IP 限流器
func (i *IPRateLimiter) CleanUpExpiredLimiters() {i.mu.Lock()defer i.mu.Unlock()for ip, lastUsed := range i.ipLastUsed {if time.Since(lastUsed) > i.ttl {delete(i.ips, ip)delete(i.ipLastUsed, ip)}}
}// 啟動一個定時器定期清理過期 IP 限流器
func (i *IPRateLimiter) StartCleanupRoutine() {go func() {for {time.Sleep(10 * time.Minute) // 每 10 分鐘執行一次清理i.CleanUpExpiredLimiters()}}()
}

3. 限流中間件

接下來,我們實現一個 RateLimitMiddleware 中間件,用于在每次請求時檢查客戶端的 IP 地址,并根據限流器的狀態判斷是否允許請求通過。

// IPRateLimitMiddleware 根據 IP 地址進行限流
func IPRateLimitMiddleware(limiter *IPRateLimiter) gin.HandlerFunc {return func(c *gin.Context) {ip := c.ClientIP()limiter := limiter.GetLimiter(ip)// 非阻塞方式檢查令牌if !limiter.Allow() {// 觸發限流,返回響應xxxxreturn}c.Next()}
}

4. 在 Gin 中使用中間件

最后,我們在 Gin 路由中使用這個中間件,并定期清理過期的 IP 限流器。

package mainimport ("github.com/gin-gonic/gin""log""time""your_project/middleware" // 引入你的中間件包
)func main() {// 創建一個 IP 限流器實例,設定每秒 10 個令牌,令牌桶容量為 100,TTL 為 1 小時ipLimiter := middleware.NewIPRateLimiter(10, 100, 1*time.Hour)// 啟動定時清理過期 IP 限流器ipLimiter.StartCleanupRoutine()// 創建 Gin 引擎r := gin.Default()// 將限流中間件應用到路由r.Use(middleware.RateLimitMiddleware2(ipLimiter))// 示例路由r.GET("/", func(c *gin.Context) {c.JSON(200, gin.H{"message": "Request successful!",})})// 啟動服務器if err := r.Run(":8080"); err != nil {log.Fatalf("Error starting server: %v", err)}
}

代碼解釋

  1. IPRateLimiter 結構體:

    • ips 存儲每個 IP 地址的限流器。
    • ipLastUsed 記錄每個 IP 地址最后一次請求的時間。
    • rb 分別是每秒生成令牌的速率和令牌桶的容量。
    • ttl 是過期時間,表示 IP 限流器的有效期。
  2. NewIPRateLimiter 初始化一個 IPRateLimiter 實例,設置速率、容量和過期時間。

  3. GetLimiter 獲取指定 IP 地址的限流器,如果限流器已經過期,會重新創建一個。

  4. CleanUpExpiredLimiters 定時清理過期的限流器。

  5. RateLimitMiddleware2 這是我們設計的限流中間件,檢查請求的 IP 地址是否符合限流條件。

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

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

相關文章

力扣 Pandas 挑戰(6)---數據合并

本文圍繞力扣的Pandas簡單題集&#xff0c;解析如何用Pandas完成基礎數據處理任務&#xff0c;適合Pandas初學者學習。題目1&#xff1a;1050. 合作過至少三次的演員和導演題目描述&#xff1a;ActorDirector 表&#xff1a;---------------------- | Column Name | Type | …

隨筆之TDengine基準測試示例

文章目錄一、基本信息二、基準測試策略三、基準測試過程1. 模擬高并發寫入場景2. 模擬并發查詢場景四、基準測試結論一、基本信息 TDengine 版本&#xff1a;3.3.6.13&#xff08;目前最新版本&#xff09;服務器配置&#xff1a;16核CPU&#xff0c;32GB內存&#xff0c;高IO…

【IQA技術專題】DISTS代碼講解

本文是對DISTS圖像質量評價指標的代碼解讀&#xff0c;原文解讀請看DISTS文章講解。 本文的代碼來源于IQA-Pytorch工程。 1、原文概要 以前的一些IQA方法對于捕捉紋理上的感知一致性有所欠缺&#xff0c;魯棒性不足。基于此&#xff0c;作者開發了一個能夠在圖像結構和圖像紋…

2024年SEVC SCI2區,一致性虛擬領航者跟蹤群集算法GDRRT*-PSO+多無人機路徑規劃,深度解析+性能實測

目錄1.摘要2.算法背景3.GDRRT*-PSO與虛擬領航者跟蹤算法4.結果展示5.參考文獻6.算法輔導應用定制讀者交流1.摘要 隨著無人機技術的快速發展及其卓越的運動和機動性能&#xff0c;無人機在社會和軍事等諸多領域得到了廣泛應用。多無人機協同作業&#xff0c;能夠顯著提升任務執…

鏈特異性文庫是什么?為什么它在轉錄組測序中越來越重要?

鏈特異性文庫是什么&#xff1f;為什么它在轉錄組測序中越來越重要&#xff1f; 在現代分子生物學研究中&#xff0c;RNA測序&#xff08;RNA-seq&#xff09; 是一種廣泛應用的技術&#xff0c;用于分析基因在不同條件下的表達情況。而在RNA-seq的眾多技術細節中&#xff0c;有…

ClickHouse vs PostgreSQL:數據分析領域的王者之爭,誰更勝一籌?

文章概要 作為一名數據架構師&#xff0c;我經常被問到一個問題&#xff1a;在眾多數據庫選擇中&#xff0c;ClickHouse和PostgreSQL哪一個更適合我的項目&#xff1f;本文將深入探討這兩種數據庫系統的核心差異、性能對比、適用場景以及各自的優缺點&#xff0c;幫助您在技術選…

面向對象系統的單元測試層次

面向對象系統的單元測試層次面向對象&#xff08;Object-Oriented, OO&#xff09;編程范式引入了封裝、繼承和多態等核心概念&#xff0c;這使得傳統的、基于函數的單元測試方法不再充分。面向對象系統的單元測試必須適應其獨特的結構和行為特性&#xff0c;從單一方法擴展到類…

如何用USRP捕獲手機信號波形(上)系統及知識準備

目錄&#xff1a; 如何用USRP捕獲手機信號波形&#xff08;上&#xff09;系統及知識準備 如何用USRP捕獲手機信號波形&#xff08;中&#xff09;手機/基站通信 如何用USRP捕獲手機信號波形&#xff08;下&#xff09;協議分析 一、手機通信參數獲取 首先用Cellular-z網絡…

C語言-數組:數組(定義、初始化、元素的訪問、遍歷)內存和內存地址、數組的查找算法和排序算法;

本章概述思維導圖&#xff1a;C語言數組在C語言中&#xff0c;數組是一種固定大小的、相同類型元素的有序集合&#xff0c;通過索引&#xff08;下標&#xff09;訪問。數組數組&#xff1a;是一種容器&#xff0c;可以用來存儲同種數據類型的多個值&#xff1b;數組特點&#…

河南萌新聯賽2025第(二)場:河南農業大學(補題)

文章目錄前言A.約數個數和整除分塊(相當于約數求和)相關例題&#xff1a;取模B.異或期望的秘密二進制的規律相關例題累加器小藍的二進制詢問乘法逆元1. 概念2.基本定義3.費馬小定理1.定理內容2.重要推論D.開羅爾網絡的備用連接方案E.咕咕嘎嘎!!!(easy)I.猜數游戲(easy)K.打瓦M.…

常見中間件漏洞

一、TomcatTomcat put方法任意文件寫入漏洞環境搭建&#xff0c;啟動時端口被占用就改yml配置文件&#xff0c;改成8081端口。(我這里是8080)cd vulhub-master/tomcat/CVE-2017-12615 docker-compose up -d 去抓包&#xff0c;改成put提交。下面的內容是用哥斯拉生成的木馬文件…

27.(vue3.x+vite)以pinia為中心的開發模板(監聽watch)

效果截圖 代碼實現: HelloWorld.vue <template><div style="padding: 20px">介紹:<br />1:使用統一的 watch 來監聽store的值。<br

Jenkins 詳解

Jenkins 是一個開源的持續集成和持續交付(CI/CD)工具&#xff0c;用于自動化軟件開發過程中的構建、測試和部署階段。以下是關于 Jenkins 的詳細介紹&#xff1a; 1. Jenkins 核心概念 1.1 持續集成(CI) 開發人員頻繁地將代碼變更提交到共享倉庫每次提交都會觸發自動構建和測試…

動態配置實現過程

查看DCCValueBeanFactory類的完整實現&#xff0c;了解動態配置的實現過程 動態配置實現過程 1. 自定義注解 使用DCCValue注解標記需要動態配置的字段&#xff0c;格式為key:defaultValue&#xff1a; DCCValue("downgradeSwitch:0") private String downgradeSw…

【大模型理論篇】跨語言AdaCOT

參考&#xff1a;AdaCoT: Rethinking Cross-Lingual Factual Reasoning throughAdaptive Chain-of-ThoughtAdaCoT&#xff08;Adaptive Chain-of-Thought&#xff0c;自適應思維鏈&#xff09;是一項提升大型語言模型&#xff08;LLMs&#xff09;跨語言事實推理能力的新框架。…

vue3項目搭建

前一段時間招聘前端開發,發現好多開發連基本的創建項目都不會,這里總結一下 在Vue 3中,使用Webpack和Vite創建的項目文件結構及語言(JS/TS)的選擇有以下主要區別: 1. 創建方式與文件結構差異 方式一、Webpack(Vue CLI) 創建命令: vue create project-name 典型文件結構…

企業簽名的多種形式

企業簽名有多種形式&#xff0c;可分為企業簽名獨立版、企業簽名穩定版、企業簽名共享版等。每一種形式的企業簽名都有其獨特的特點&#xff0c;其中&#xff1a;  企業簽名獨立版&#xff1a;其特性主要為穩定性較高&#xff0c;使用者可以通過控制APP的下載量來保證APP的穩…

解構遠程智能系統的視頻能力鏈:從RTSP|RTMP協議接入到Unity3D頭顯呈現全流程指南

在人工智能奔騰的2025年&#xff0c;WAIC&#xff08;世界人工智能大會&#xff09;釋放出一個明確信號&#xff1a;視頻能力已經成為通往“遠程智能”的神經中樞。在無人機、四足機器人、遠程施工、巡檢等新興場景中&#xff0c;一套可靠、低延遲、可嵌入頭顯設備的視頻傳輸系…

Less Less基礎

1.lessless是一種動態樣式語言&#xff0c;屬于CSS預處理器的范疇&#xff0c;它擴展了CSS語言&#xff0c;增加了變量&#xff0c;Mixin&#xff0c;函數等特性&#xff0c;使CSS更易維護和擴展。Less既可以在客戶端上運行&#xff0c;也可以借助Node.js在服務端運行。2.Less中…

如何使用 Redis 實現 API 網關或單個服務的請求限流?

使用 Redis 高效實現 API 網關與服務的請求限流 在微服務架構中&#xff0c;對 API 網關或單個服務的請求進行速率限制至關重要&#xff0c;以防止惡意攻擊、資源濫用并確保系統的穩定性和可用性。 Redis 憑借其高性能、原子操作和豐富的數據結構&#xff0c;成為實現請求限流的…