首頁 >後端開發 >Golang >初學者的速率限制:它是什麼以及如何在 Go 中構建速率限制

初學者的速率限制:它是什麼以及如何在 Go 中構建速率限制

Barbara Streisand
Barbara Streisand原創
2025-01-01 07:58:10582瀏覽

速率限制是 Web 開發和 API 設計中的關鍵概念。它確保使用者或系統在特定時間範圍內只能向伺服器發出有限數量的請求。在這篇文章中,我們將探討什麼是速率限制、為什麼它很重要,以及如何在 Go 中實作一個簡單的速率限制器。

Rate Limiting for Beginners: What It Is and How to Build One in Go

什麼是速率限制?

想像一個主題樂園,裡面有雲霄飛車,每 10 分鐘只能容納 10 人。如果超過 10 人試圖在該時間內上車,他們將不得不等待。這個類比反映了軟體系統中速率限制的原理。

用技術術語來說,速率限制限制客戶端(例如使用者、裝置或 IP 位址)在預定義時間內可以傳送到伺服器的請求數量。它有幫助:

  1. 防止濫用並確保公平使用資源。
  2. 保護伺服器不被過多的流量淹沒。
  3. 避免過度使用第三方 API 或服務,造成高昂代價。

例如,API 可能允許每位使用者每分鐘 100 個請求。如果使用者超出此限制,伺服器將拒絕進一步的請求,直到限制重置。

速率限制如何運作?

實現速率限制的常見方法是透過令牌桶演算法。其工作原理如下:

  1. 儲存桶以固定數量的令牌(例如 10)開始。
  2. 每個請求都會從儲存桶中刪除一個令牌。
  3. 如果桶中沒有剩餘令牌,則請求被拒絕。
  4. 代幣會以穩定的速度(例如每秒 1 個代幣)補充,直到桶裝滿。

在 Go 中建立一個簡單的速率限制器

讓我們深入研究在 Go 中建立一個速率限制器,將每個客戶端限制為每分鐘 3 個請求。

第 1 步:定義速率限制器結構

我們將使用sync.Mutex來確保執行緒安全性並儲存令牌數量、最大容量和填充率等資訊。

package main

import (
    "sync"
    "time"
)

type RateLimiter struct {
    tokens         float64   // Current number of tokens
    maxTokens      float64   // Maximum tokens allowed
    refillRate     float64   // Tokens added per second
    lastRefillTime time.Time // Last time tokens were refilled
    mutex          sync.Mutex
}

func NewRateLimiter(maxTokens, refillRate float64) *RateLimiter {
    return &RateLimiter{
        tokens:         maxTokens,
        maxTokens:      maxTokens,
        refillRate:     refillRate,
        lastRefillTime: time.Now(),
    }
}

第 2 步:實作令牌補充邏輯

代幣應根據上次充值以來的經過時間定期補充。

func (r *RateLimiter) refillTokens() {
    now := time.Now()
    duration := now.Sub(r.lastRefillTime).Seconds()
    tokensToAdd := duration * r.refillRate

    r.tokens += tokensToAdd
    if r.tokens > r.maxTokens {
        r.tokens = r.maxTokens
    }
    r.lastRefillTime = now
}

第 3 步:檢查請求是否被允許

Allow 方法將根據可用令牌確定請求是否可以繼續。

func (r *RateLimiter) Allow() bool {
    r.mutex.Lock()
    defer r.mutex.Unlock()

    r.refillTokens()

    if r.tokens >= 1 {
        r.tokens--
        return true
    }
    return false
}

第 4 步:對每個 IP 應用速率限制

為了限制每個客戶端的請求,我們將建立 IP 位址到各自速率限制器的對應。

type IPRateLimiter struct {
    limiters map[string]*RateLimiter
    mutex    sync.Mutex
}

func NewIPRateLimiter() *IPRateLimiter {
    return &IPRateLimiter{
        limiters: make(map[string]*RateLimiter),
    }
}

func (i *IPRateLimiter) GetLimiter(ip string) *RateLimiter {
    i.mutex.Lock()
    defer i.mutex.Unlock()

    limiter, exists := i.limiters[ip]
    if !exists {
        // Allow 3 requests per minute
        limiter = NewRateLimiter(3, 0.05)
        i.limiters[ip] = limiter
    }

    return limiter
}

第 5 步:建立用於速率限制的中間件

最後,我們將建立一個 HTTP 中間件,對每個客戶端實作速率限制。

package main

import (
    "sync"
    "time"
)

type RateLimiter struct {
    tokens         float64   // Current number of tokens
    maxTokens      float64   // Maximum tokens allowed
    refillRate     float64   // Tokens added per second
    lastRefillTime time.Time // Last time tokens were refilled
    mutex          sync.Mutex
}

func NewRateLimiter(maxTokens, refillRate float64) *RateLimiter {
    return &RateLimiter{
        tokens:         maxTokens,
        maxTokens:      maxTokens,
        refillRate:     refillRate,
        lastRefillTime: time.Now(),
    }
}

第 6 步:設定伺服器

以下是如何將它們連接在一起並測試速率限制器。

func (r *RateLimiter) refillTokens() {
    now := time.Now()
    duration := now.Sub(r.lastRefillTime).Seconds()
    tokensToAdd := duration * r.refillRate

    r.tokens += tokensToAdd
    if r.tokens > r.maxTokens {
        r.tokens = r.maxTokens
    }
    r.lastRefillTime = now
}

測試速率限制器

啟動伺服器並使用curl或瀏覽器測試:

func (r *RateLimiter) Allow() bool {
    r.mutex.Lock()
    defer r.mutex.Unlock()

    r.refillTokens()

    if r.tokens >= 1 {
        r.tokens--
        return true
    }
    return false
}
  • 快速發送 3 個請求:全部都應該成功。
  • 在同一分鐘內發送第四個請求:您應該會看到「超出速率限制」訊息。
  • 等待 20 秒,然後重試:儲存桶重新裝滿,請求應該會成功。

原始碼

GitHub 儲存庫

以上是初學者的速率限制:它是什麼以及如何在 Go 中構建速率限制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn