最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang編寫自定義IP限流中間件的方法詳解

 更新時(shí)間:2023年09月18日 09:21:51   作者:小小小熊貓5  
這篇文章給大家詳細(xì)的介紹了Golang編寫自定義IP限流中間件的方法,文章通過代碼實(shí)例介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下

基于令牌桶的限流算法

  • r:每秒鐘向桶內(nèi)放入 r 個(gè)令牌,即每隔 1/r秒放一個(gè)令牌
  • b:桶的最大容量是 b,桶滿后試圖再放入的令牌會(huì)被丟棄掉
  • 當(dāng)有人請(qǐng)求 n 個(gè)令牌時(shí),如果桶中的令牌數(shù)小于n,則請(qǐng)求放阻塞或直接放棄,否則順利從桶中取走 n 個(gè)令牌
    • 當(dāng) b > 1 時(shí),任意 1/r 秒內(nèi)最多可以取走 b 個(gè)令牌
      • 限制很短的一個(gè)瞬間的一個(gè)最高的并發(fā)量,b=最高的并發(fā)量,r=最短的時(shí)間段
    • 當(dāng) b = 1 時(shí),每秒鐘最多可被取走 r 個(gè)令牌
      • 限制每秒鐘的最高的QPS:b=1,r=最高的QPS
      • 限制每分鐘的最高請(qǐng)求量:把每分鐘的請(qǐng)求量/60=轉(zhuǎn)換成1秒鐘,賦給 r 就可以了
      • 限制每5分鐘、每10分鐘,同理

實(shí)現(xiàn)高并發(fā)限流(使用golang官方限流器)

Go代碼

源碼地址: GitHub-golang版本

middleware/rateLimiterMiddleware.go

package middleware
import (
	"net/http"
	"time"
	"github.com/gin-gonic/gin"
	"golang.org/x/time/rate"
)
var Limiter *rate.Limiter
// 定義一個(gè)中間件函數(shù)來進(jìn)行限流
func RateLimiterMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		if !Limiter.AllowN(time.Now(), 1) {
			c.JSON(http.StatusTooManyRequests, gin.H{"message": "Rate limit exceeded"})
			// 設(shè)置休眠和業(yè)務(wù)時(shí)長一樣,為了更好從日志出看出規(guī)則
			time.Sleep(50 * time.Millisecond)
			c.Abort()
			return
		}
		c.Next()
	}
}

main.go

func main() {
	r := gin.Default()
	// 創(chuàng)建一個(gè)限流器,每秒允許最多10個(gè)請(qǐng)求
	middleware.Limiter = rate.NewLimiter(rate.Limit(10), 1)
	// 使用限流中間件
	r.Use(middleware.RateLimiterMiddleware())
	r.GET("/api/resource", func(c *gin.Context) {
		time.Sleep(50 * time.Millisecond)
		c.JSON(http.StatusOK, gin.H{"message": "Resource accessed"})
	})
	r.Run(":8080")
}

測(cè)試記錄

ab -t 1 -c 1 http://127.0.0.1:8080/api/resource

使用ab壓力測(cè)試,并發(fā)量為1的(相當(dāng)于串行),在1秒內(nèi)不斷發(fā)出請(qǐng)求(算下來,每個(gè)請(qǐng)求50ms,總共能發(fā)出20個(gè)請(qǐng)求)

結(jié)果預(yù)測(cè):1秒內(nèi)最多生成10個(gè)令牌,而總共有20個(gè)串行的請(qǐng)求,結(jié)果應(yīng)該是1個(gè)成功(在50ms結(jié)束),1個(gè)失?。ê?0ms內(nèi)還未有新的令牌生成),1個(gè)成功,1個(gè)失敗。。。 結(jié)果輸出(符合預(yù)期)

在這里插入圖片描述

在這里插入圖片描述

升級(jí):根據(jù)每個(gè)IP地址進(jìn)行限流

Go代碼

源碼地址: GitHub-golang版本

middleware/ipRateLimiterMiddleware.go

package middleware
import (
	"net/http"
	"sync"
	"time"
	"github.com/gin-gonic/gin"
	"golang.org/x/time/rate"
)
var IPLimiter *IPRateLimiter
func NewIPRateLimiter() *IPRateLimiter {
	return &IPRateLimiter{
		limiter: make(map[string]*rate.Limiter),
	}
}
type IPRateLimiter struct {
	mu      sync.Mutex
	limiter map[string]*rate.Limiter
}
func (i *IPRateLimiter) GetLimiter(ip string) *rate.Limiter {
	i.mu.Lock()
	defer i.mu.Unlock()
	limiter, exists := i.limiter[ip]
	if !exists {
		limiter = rate.NewLimiter(2, 5) // 每秒2個(gè)請(qǐng)求,桶容量為5
		i.limiter[ip] = limiter
	}
	return limiter
}
// 定義一個(gè)中間件函數(shù)來進(jìn)行限流
func IPRateLimiterMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		ip := c.ClientIP()
		limiter := IPLimiter.GetLimiter(ip)
		if !limiter.Allow() {
			c.JSON(http.StatusTooManyRequests, gin.H{"message": "Rate limit exceeded"})
			// 設(shè)置休眠和業(yè)務(wù)時(shí)長一樣,為了更好從日志出看出規(guī)則
			time.Sleep(50 * time.Millisecond)
			c.Abort()
			return
		}
		c.Next()
	}
}

main.go

func main() {
	r := gin.Default()
	// 創(chuàng)建IP限流器
	middleware.IPLimiter = middleware.NewIPRateLimiter()
	// 使用限流中間件
	r.Use(middleware.IPRateLimiterMiddleware())
	r.GET("/api/resource", func(c *gin.Context) {
		time.Sleep(50 * time.Millisecond)
		c.JSON(http.StatusOK, gin.H{"message": "Resource accessed"})
	})
	r.Run(":8080")
}

測(cè)試記錄

ab -t 1 -c 1 http://127.0.0.1:8080/api/resource

使用ab壓力測(cè)試,并發(fā)量為1的(相當(dāng)于串行),在1秒內(nèi)不斷發(fā)出請(qǐng)求(算下來,每個(gè)請(qǐng)求50ms,總共能發(fā)出20個(gè)請(qǐng)求)

結(jié)果預(yù)測(cè):1秒內(nèi)最多生成2個(gè)令牌,桶容量為5 代表在1/2秒內(nèi)的最大并發(fā)量是5,總共有20個(gè)串行的請(qǐng)求,結(jié)果應(yīng)該是先成功5個(gè)(桶容量全使用成功), 之后剩余成功的是1個(gè),其余全部失敗

  • 當(dāng)程序啟動(dòng)時(shí),限流器初始化,桶是空的,沒有令牌。
  • 在每秒的前兩次令牌生成中,每次生成2個(gè)令牌,并放入桶中。
  • 在第3秒,生成的2個(gè)令牌中只有1個(gè)能夠被放入桶中,因?yàn)橥耙呀?jīng)滿了。
  • 當(dāng)使用ab發(fā)出請(qǐng)求時(shí),前5個(gè)請(qǐng)求依次拿到了令牌并成功,每個(gè)請(qǐng)求耗時(shí)50ms。此時(shí)總耗時(shí)為250ms。
  • 第6個(gè)請(qǐng)求在300ms,第7個(gè)請(qǐng)求在350ms,第8個(gè)請(qǐng)求在400ms,第9個(gè)請(qǐng)求在450ms,第10個(gè)請(qǐng)求在500ms。
  • 因?yàn)橄蘖髌鞯乃俾适敲棵?個(gè)請(qǐng)求,也就是每500ms生成一個(gè)令牌。 第500ms時(shí)新的令牌生成,所以第6-10請(qǐng)求期間,是沒有令牌的,所以都請(qǐng)求失敗,而11個(gè)請(qǐng)求時(shí)有新令牌生成,所以能成功。
  • 之后的請(qǐng)求以此類推,需要等待新令牌生成。

結(jié)果輸出(符合預(yù)期)

在這里插入圖片描述

在這里插入圖片描述

以上就是Golang編寫自定義IP限流中間件的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于Golang編寫IP限流中間件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 從生成CRD到編寫自定義控制器教程示例

    從生成CRD到編寫自定義控制器教程示例

    這篇文章主要為大家介紹了從生成CRD到編寫自定義控制器的教程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • Go快速開發(fā)一個(gè)RESTful API服務(wù)

    Go快速開發(fā)一個(gè)RESTful API服務(wù)

    這篇文章主要為大家介紹了Go快速開發(fā)一個(gè)RESTful API服務(wù),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • go語言日志實(shí)現(xiàn)詳解(打印日志、日志寫入文件和日志切割)

    go語言日志實(shí)現(xiàn)詳解(打印日志、日志寫入文件和日志切割)

    golang內(nèi)置了log包,實(shí)現(xiàn)簡單的日志服務(wù),下面這篇文章主要給大家介紹了關(guān)于go語言日志實(shí)現(xiàn)(打印日志、日志寫入文件和日志切割)的相關(guān)資料,需要的朋友可以參考下
    2022-10-10
  • go-zero?組件布隆過濾器使用示例詳解

    go-zero?組件布隆過濾器使用示例詳解

    這篇文章主要為大家介紹了go-zero組件介紹之布隆過濾器使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • Golang WaitGroup實(shí)現(xiàn)原理解析

    Golang WaitGroup實(shí)現(xiàn)原理解析

    WaitGroup是Golang并發(fā)的兩種方式之一,一個(gè)是Channel,另一個(gè)是WaitGroup,下面這篇文章主要給大家介紹了關(guān)于golang基礎(chǔ)之waitgroup用法以及使用要點(diǎn)的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • Go語言七篇入門教程二程序結(jié)構(gòu)與數(shù)據(jù)類型

    Go語言七篇入門教程二程序結(jié)構(gòu)與數(shù)據(jù)類型

    這篇文章主要為大家介紹了Go語言的程序結(jié)構(gòu)與數(shù)據(jù)類型,本篇文章是Go語言七篇入門系列文,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2021-11-11
  • Golang常用環(huán)境變量說明與設(shè)置詳解

    Golang常用環(huán)境變量說明與設(shè)置詳解

    這篇文章主要介紹了Golang常用環(huán)境變量說明與設(shè)置,需要的朋友可以參考下
    2020-02-02
  • 基于Go語言實(shí)現(xiàn)簡單的計(jì)算器

    基于Go語言實(shí)現(xiàn)簡單的計(jì)算器

    這篇文章主要為大家詳細(xì)介紹了如何基于Go語言實(shí)現(xiàn)簡單的計(jì)算器,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-10-10
  • Golang使用sqlite3數(shù)據(jù)庫實(shí)現(xiàn)CURD操作

    Golang使用sqlite3數(shù)據(jù)庫實(shí)現(xiàn)CURD操作

    這篇文章主要為大家詳細(xì)介紹了Golang使用sqlite3數(shù)據(jù)庫實(shí)現(xiàn)CURD操作的相關(guān)知識(shí),文中的示例代碼簡潔易懂,有需要的小伙伴可以參考一下
    2025-03-03
  • Go語言切片(Slice)使用技巧與避坑指南

    Go語言切片(Slice)使用技巧與避坑指南

    切片(Slice)是Go語言中最靈活且高頻使用的數(shù)據(jù)結(jié)構(gòu)之一,其本質(zhì)是對(duì)底層數(shù)組的動(dòng)態(tài)引用視圖,支持動(dòng)態(tài)擴(kuò)容、高效截取等特性,本文將結(jié)合代碼示例,詳細(xì)解析切片的核心用法及常見注意事項(xiàng),需要的朋友可以參考下
    2025-06-06

最新評(píng)論

大宁县| 建昌县| 潮安县| 长岭县| 荆州市| 高碑店市| 东阳市| 淮南市| 贵德县| 陆河县| 大庆市| 顺平县| 高淳县| 彭州市| 和静县| 广西| 德保县| 威信县| 武平县| 湘阴县| 漳平市| 滨海县| 报价| 绍兴县| 香河县| 封丘县| 阳山县| 望江县| 新民市| 加查县| 宁夏| 梅州市| 厦门市| 凤城市| 辽源市| 昆山市| 临桂县| 临泽县| 仙居县| 皮山县| 桦川县|