Go語(yǔ)言使用漏桶算法和令牌桶算法來(lái)實(shí)現(xiàn)API限流
在現(xiàn)代 Web 應(yīng)用程序中,流量的突增是不可避免的。為防止服務(wù)器被過(guò)多的請(qǐng)求壓垮,限流(Rate Limiting) 是一個(gè)至關(guān)重要的技術(shù)手段。
本文將通過(guò) Go 語(yǔ)言的 Gin 框架,演示如何使用漏桶算法和令牌桶算法來(lái)實(shí)現(xiàn) API 的限流。
限流的意義
限流的主要目的是保護(hù)系統(tǒng)資源,防止因請(qǐng)求量過(guò)大導(dǎo)致服務(wù)器崩潰。同時(shí),它也能防止惡意用戶(hù)對(duì)系統(tǒng)的攻擊,確保服務(wù)的穩(wěn)定性和可用性。
兩種常見(jiàn)的限流算法
1.漏桶算法(Leaky Bucket)
漏桶算法將請(qǐng)求視為水滴,水滴先進(jìn)入桶中,然后以固定的速率從桶中流出。如果請(qǐng)求的速率超過(guò)了桶的流出速率,多余的請(qǐng)求將會(huì)被丟棄。
這個(gè)算法的優(yōu)點(diǎn)很明顯,就是讓請(qǐng)求非常穩(wěn)定,但是缺點(diǎn)也很明顯,因?yàn)檎?qǐng)求非常穩(wěn)定,就不適于一些秒殺等一些可能在某一段時(shí)間會(huì)有洪峰流量的場(chǎng)景。不太好適情況控制流量的進(jìn)入。
2.令牌桶算法(Token Bucket)
令牌桶算法中,系統(tǒng)會(huì)以固定的速率向桶中加入令牌,每個(gè)請(qǐng)求需要獲取一個(gè)令牌才能執(zhí)行。如果桶中沒(méi)有足夠的令牌,請(qǐng)求將被拒絕。
代碼實(shí)現(xiàn)
在這個(gè)示例中,我們將展示如何在 Gin 框架中應(yīng)用這兩種算法來(lái)實(shí)現(xiàn) API 的限流。
package main
import (
"fmt"
"net/http"
"time"
"github.com/gin-gonic/gin"
ratelimit2 "github.com/juju/ratelimit" // 令牌桶算法
ratelimit1 "go.uber.org/ratelimit" // 漏桶算法
)
func pingHandler(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
}
func pingHandler2(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong2",
})
}
// rateLimit1 使用漏桶算法來(lái)限制請(qǐng)求速率
func rateLimit1() func(ctx *gin.Context) {
// 漏桶算法,第一個(gè)參數(shù)為兩滴水滴之間的時(shí)間間隔。
// 此時(shí)表示兩滴水之間的時(shí)間間隔是 100 納秒
rl := ratelimit1.New(100)
return func(ctx *gin.Context) {
// 嘗試取出水滴
if waitTime := rl.Take().Sub(time.Now()); waitTime > 0 {
fmt.Printf("需要等待 %v 秒,下一滴水才會(huì)滴下來(lái)\n", waitTime)
// 這里我們可以讓程序繼續(xù)等待,也可以直接拒絕掉
// time.Sleep(waitTime)
ctx.String(http.StatusOK, "rate limit, try again later")
ctx.Abort()
return
}
// 證明可以繼續(xù)執(zhí)行
ctx.Next()
}
}
// rateLimit2 使用令牌桶算法來(lái)限制請(qǐng)求速率
func rateLimit2() func(ctx *gin.Context) {
// 令牌桶算法:第一個(gè)參數(shù)為每秒填充令牌的速率為多少
// 第二個(gè)參數(shù)為令牌桶的容量
// 這里表示每秒填充 10 個(gè)令牌
rl := ratelimit2.NewBucket(time.Second, 10)
return func(ctx *gin.Context) {
// 嘗試取出令牌
var num int64 = 1
// 這里表示需要 num 個(gè)令牌和已經(jīng)取出的令牌數(shù)是否相等
// 不相等,則表示超過(guò)了限流
// 比如,假設(shè)每一個(gè)請(qǐng)求過(guò)來(lái)消耗2個(gè)令牌,但是從桶中取出的令牌個(gè)數(shù)為 1 ,那么則認(rèn)為超過(guò)了限流(一般而言是一個(gè)請(qǐng)求消耗一個(gè)令牌,這里僅為舉例)
if rl.TakeAvailable(num) != num {
// 此次沒(méi)有取到令牌,說(shuō)明超過(guò)了限流
ctx.String(http.StatusOK, "rate limit, try again later")
ctx.Abort()
return
}
// 證明可以繼續(xù)執(zhí)行
ctx.Next()
}
}
func main() {
r := gin.Default()
// 漏桶算法限流
r.GET("/ping", rateLimit1(), pingHandler)
// 令牌桶算法限流
r.GET("/ping2", rateLimit2(), pingHandler2)
r.Run()
}
代碼解析
漏桶算法的實(shí)現(xiàn)(rateLimit1 函數(shù))
- 通過(guò)
go.uber.org/ratelimit包中的ratelimit.New方法創(chuàng)建了一個(gè)限流器。 - 當(dāng)請(qǐng)求速率超過(guò)限流器的處理能力時(shí),請(qǐng)求將被拒絕,并返回 "rate limit, try again later"。
令牌桶算法的實(shí)現(xiàn)(rateLimit2 函數(shù))
- 使用
github.com/juju/ratelimit包實(shí)現(xiàn)了令牌桶算法。每秒填充一定數(shù)量的令牌到桶中。 - 如果桶中沒(méi)有足夠的令牌,請(qǐng)求將被拒絕。
Gin 路由配置
在 main 函數(shù)中,通過(guò) rateLimit1 和 rateLimit2 中間件為 /ping 和 /ping2 路由分別設(shè)置了漏桶和令牌桶限流。
總結(jié)
在本文中,我們演示了如何在 Go 中使用漏桶算法和令牌桶算法實(shí)現(xiàn) API 的限流。
這些算法在高并發(fā)的 Web 服務(wù)中非常有用,可以有效防止服務(wù)被大量請(qǐng)求淹沒(méi),確保系統(tǒng)的穩(wěn)定性。希望通過(guò)這篇文章,您能更好地理解并應(yīng)用這些限流技術(shù)到您的項(xiàng)目中。
以上就是Go語(yǔ)言使用漏桶算法和令牌桶算法來(lái)實(shí)現(xiàn)API限流的詳細(xì)內(nèi)容,更多關(guān)于Go API限流的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Golang回調(diào)函數(shù)與閉包和接口函數(shù)的定義及使用介紹
這篇文章主要介紹了Golang回調(diào)函數(shù)與閉包和接口函數(shù)的定義及使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-05-05
Golang使用Gin框架實(shí)現(xiàn)HTTP響應(yīng)格式統(tǒng)一處理
在gin框架中,我們可以定義一個(gè)中間件來(lái)處理統(tǒng)一的HTTP響應(yīng)格式,本文主要為大家介紹了具體是怎么定義實(shí)現(xiàn)這樣的中間件的,感興趣的小伙伴可以了解一下2023-07-07
Go string轉(zhuǎn)int,int64,int32及注意事項(xiàng)說(shuō)明
這篇文章主要介紹了Go string轉(zhuǎn)int,int64,int32及注意事項(xiàng)說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07
golang?http請(qǐng)求未釋放造成的錯(cuò)誤問(wèn)題
這篇文章主要介紹了golang?http請(qǐng)求未釋放造成的錯(cuò)誤問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01
Go?gRPC進(jìn)階教程gRPC轉(zhuǎn)換HTTP
這篇文章主要為大家介紹了Go?gRPC進(jìn)階教程gRPC轉(zhuǎn)換HTTP教程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
Golang?Template實(shí)現(xiàn)自定義函數(shù)的操作指南
這篇文章主要為大家詳細(xì)介紹了Golang如何利用Template實(shí)現(xiàn)自定義函數(shù)的操作,文中的示例代碼簡(jiǎn)潔易懂,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-02-02

