使用漏桶和令牌桶實現(xiàn)API速率限制

在現(xiàn)代 Web 應(yīng)用程序中珍逸,流量的突增是不可避免的僧免。為防止服務(wù)器被過多的請求壓垮,限流(Rate Limiting) 是一個至關(guān)重要的技術(shù)手段克伊。

本文將通過 Go 語言的 Gin 框架酥郭,演示如何使用漏桶算法令牌桶算法來實現(xiàn) API 的限流。

限流的意義

限流的主要目的是保護系統(tǒng)資源愿吹,防止因請求量過大導致服務(wù)器崩潰不从。同時,它也能防止惡意用戶對系統(tǒng)的攻擊犁跪,確保服務(wù)的穩(wěn)定性和可用性椿息。

兩種常見的限流算法

  1. 漏桶算法(Leaky Bucket)

漏桶算法將請求視為水滴,水滴先進入桶中坷衍,然后以固定的速率從桶中流出寝优。如果請求的速率超過了桶的流出速率,多余的請求將會被丟棄枫耳。

這個算法的優(yōu)點很明顯乏矾,就是讓請求非常穩(wěn)定,但是缺點也很明顯迁杨,因為請求非常穩(wěn)定钻心,就不適于一些秒殺等一些可能在某一段時間會有洪峰流量的場景。不太好適情況控制流量的進入铅协。

  1. 令牌桶算法(Token Bucket)

令牌桶算法中捷沸,系統(tǒng)會以固定的速率向桶中加入令牌,每個請求需要獲取一個令牌才能執(zhí)行狐史。如果桶中沒有足夠的令牌痒给,請求將被拒絕。

代碼實現(xiàn)

在這個示例中骏全,我們將展示如何在 Gin 框架中應(yīng)用這兩種算法來實現(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 使用漏桶算法來限制請求速率
func rateLimit1() func(ctx *gin.Context) {
    // 漏桶算法,第一個參數(shù)為兩滴水滴之間的時間間隔吟温。
    // 此時表示兩滴水之間的時間間隔是 100 納秒
    rl := ratelimit1.New(100)

    return func(ctx *gin.Context) {
        // 嘗試取出水滴
        if waitTime := rl.Take().Sub(time.Now()); waitTime > 0 {
            fmt.Printf("需要等待 %v 秒,下一滴水才會滴下來\n", waitTime)
            // 這里我們可以讓程序繼續(xù)等待突颊,也可以直接拒絕掉
            // time.Sleep(waitTime)
            ctx.String(http.StatusOK, "rate limit, try again later")
            ctx.Abort()
            return
        }
        // 證明可以繼續(xù)執(zhí)行
        ctx.Next()
    }
}

// rateLimit2 使用令牌桶算法來限制請求速率
func rateLimit2() func(ctx *gin.Context) {
    // 令牌桶算法:第一個參數(shù)為每秒填充令牌的速率為多少
    // 第二個參數(shù)為令牌桶的容量
    // 這里表示每秒填充 10 個令牌
    rl := ratelimit2.NewBucket(time.Second, 10)

    return func(ctx *gin.Context) {
        // 嘗試取出令牌
        var num int64 = 1
        // 這里表示需要 num 個令牌和已經(jīng)取出的令牌數(shù)是否相等
        // 不相等鲁豪,則表示超過了限流
                // 比如,假設(shè)每一個請求過來消耗2個令牌律秃,但是從桶中取出的令牌個數(shù)為 1 爬橡,那么則認為超過了限流(一般而言是一個請求消耗一個令牌,這里僅為舉例)
        if rl.TakeAvailable(num) != num {
            // 此次沒有取到令牌棒动,說明超過了限流
            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()
}

代碼解析

  1. 漏桶算法的實現(xiàn)(rateLimit1 函數(shù))

    • 通過 go.uber.org/ratelimit 包中的 ratelimit.New 方法創(chuàng)建了一個限流器糙申。
    • 當請求速率超過限流器的處理能力時,請求將被拒絕船惨,并返回 "rate limit, try again later"柜裸。
  2. 令牌桶算法的實現(xiàn)(rateLimit2 函數(shù))

    • 使用 github.com/juju/ratelimit 包實現(xiàn)了令牌桶算法缕陕。每秒填充一定數(shù)量的令牌到桶中。
    • 如果桶中沒有足夠的令牌疙挺,請求將被拒絕扛邑。
  3. Gin 路由配置

    • main 函數(shù)中,通過 rateLimit1rateLimit2 中間件為 /ping/ping2 路由分別設(shè)置了漏桶和令牌桶限流铐然。

總結(jié)

在本文中蔬崩,我們演示了如何在 Go 中使用漏桶算法和令牌桶算法實現(xiàn) API 的限流。

這些算法在高并發(fā)的 Web 服務(wù)中非常有用搀暑,可以有效防止服務(wù)被大量請求淹沒沥阳,確保系統(tǒng)的穩(wěn)定性。希望通過這篇文章自点,您能更好地理解并應(yīng)用這些限流技術(shù)到您的項目中桐罕。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市樟氢,隨后出現(xiàn)的幾起案子冈绊,更是在濱河造成了極大的恐慌,老刑警劉巖埠啃,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件死宣,死亡現(xiàn)場離奇詭異,居然都是意外死亡碴开,警方通過查閱死者的電腦和手機毅该,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來潦牛,“玉大人眶掌,你說我怎么就攤上這事“屯耄” “怎么了朴爬?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長橡淆。 經(jīng)常有香客問我召噩,道長,這世上最難降的妖魔是什么逸爵? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任具滴,我火速辦了婚禮,結(jié)果婚禮上师倔,老公的妹妹穿的比我還像新娘构韵。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布疲恢。 她就那樣靜靜地躺著凶朗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪冈闭。 梳的紋絲不亂的頭發(fā)上俱尼,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音萎攒,去河邊找鬼遇八。 笑死,一個胖子當著我的面吹牛耍休,可吹牛的內(nèi)容都是我干的刃永。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼羊精,長吁一口氣:“原來是場噩夢啊……” “哼斯够!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起喧锦,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤读规,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后燃少,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體束亏,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年阵具,在試婚紗的時候發(fā)現(xiàn)自己被綠了碍遍。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡阳液,死狀恐怖怕敬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情帘皿,我是刑警寧澤东跪,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站鹰溜,受9級特大地震影響虽填,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜奉狈,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望涩惑。 院中可真熱鬧仁期,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至赊级,卻和暖如春押框,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背理逊。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工橡伞, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人晋被。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓兑徘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親羡洛。 傳聞我的和親對象是個殘疾皇子挂脑,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容