go rate 原生標(biāo)準(zhǔn)限速庫的使用
在我們實(shí)際生產(chǎn)開發(fā)過程中,不免存在一些高并發(fā)的場景,此時(shí)我們就需要對請求進(jìn)行限流,避免過高的QPS,影響我們服務(wù)器,導(dǎo)致服務(wù)出現(xiàn)波動(dòng)或不可用。
- 對于go開發(fā)人員而言,golang標(biāo)準(zhǔn)庫就已經(jīng)為我們提供了現(xiàn)成的類庫
golang.org/x/time/rate,我們只需直接調(diào)用即可。下面將為大家介紹該類庫的詳細(xì)用法。
文中代碼地址,歡迎大家??:https://github.com/ziyifast/ziyifast-code_instruction/tree/main/go-demo/go-rate
介紹
限流(Rate Limiting)是控制對某些資源訪問頻率的一種技術(shù)手段。在高并發(fā)的服務(wù)中,限流機(jī)制可以有效防止資源過載、服務(wù)崩潰,保障系統(tǒng)的穩(wěn)定性和可用性。Golang 官方標(biāo)準(zhǔn)庫 golang.org/x/time/rate 提供了一個(gè)高效且易用的限流器(Rate Limiter),可以幫助開發(fā)者方便地實(shí)現(xiàn)限流功能。
原理:golang官方的類庫采用了令牌桶算法進(jìn)行限流。
- 令牌桶算法(Token Bucket Algorithm):是一種常用的限流算法,它通過在固定時(shí)間間隔內(nèi)向“桶”中添加“令牌”,請求在處理前需要從桶中獲取令牌。如果桶中有足夠的令牌,請求被處理;否則,請求被拒絕或等待。
- 速率(Rate):速率定義了令牌添加的速度,即每秒向桶中添加多少令牌。
- 容量(Burst):容量定義了桶的大小,即桶中最多可以存儲(chǔ)多少令牌。它決定了在一段時(shí)間內(nèi)允許的最大突發(fā)請求數(shù)。
安裝
go get golang.org/x/time/rate
API介紹
rate.NewLimiter:創(chuàng)建限流器
創(chuàng)建限流器后,可以通過 Allow、Reserve、Wait 等方法請求許可
package main
import (
"fmt"
"golang.org/x/time/rate"
"time"
)
func main() {
// 每秒生成3個(gè)令牌,桶的容量為10個(gè)令牌
// 相當(dāng)于每秒最多能處理三個(gè)請求,順時(shí)并發(fā)最多能處理10個(gè)請求
limiter := rate.NewLimiter(3, 10)
fmt.Println("Limiter created with rate 3 tokens per second and burst size of 10")
}
limiter.Allow():請求是否被允許/限流
Allow 方法立即返回一個(gè)布爾值,指示請求是否被允許
if limiter.Allow() {
fmt.Println("Request allowed")
} else {
fmt.Println("Request denied")
}
limiter.Reserve():返回值包含了許可時(shí)間和是否可用的信息
Reserve 方法返回一個(gè) Reservation 對象,包含了許可時(shí)間和是否可用的信息
reservation := limiter.Reserve()
if reservation.OK() {
fmt.Println("Request reserved, delay:", reservation.Delay())
} else {
fmt.Println("Request cannot be reserved")
}
limiter.Wait(ctx):阻塞當(dāng)前協(xié)程,直到允許請求或上下文取消
Wait 方法阻塞當(dāng)前協(xié)程,直到允許請求或上下文取消
ctx := context.Background()
if err := limiter.Wait(ctx); err == nil {
fmt.Println("Request allowed after wait")
} else {
fmt.Println("Request denied:", err)
}
實(shí)戰(zhàn)使用
并發(fā)處理任務(wù)
一段時(shí)間內(nèi),限制服務(wù)器處理任務(wù)數(shù)
// Demo_CurrentHandleWorks 模擬并發(fā)處理任務(wù)
func Demo_CurrentHandleWorks() {
var wg sync.WaitGroup
numWorkers := 5 // 模擬5個(gè)并發(fā)請求
// 構(gòu)造限流器:每10s向桶中新增一個(gè)令牌,桶里最多能存放2個(gè)令牌 => 每10s能處理一個(gè)任務(wù),一定時(shí)間內(nèi)最多能處理2個(gè)任務(wù)(令牌有剩余)
var l = rate.NewLimiter(rate.Every(time.Second*10), 2)
for i := 1; i <= numWorkers; i++ {
wg.Add(1)
go worker(i, &wg, l)
}
wg.Wait()
}
func worker(id int, wg *sync.WaitGroup, limiter *rate.Limiter) {
defer wg.Done()
if limiter.Allow() {
fmt.Printf("Worker %d processed at %s\n", id, time.Now().Format("15:04:05.000"))
} else {
fmt.Printf("Worker %d rejected at %s\n", id, time.Now().Format("15:04:05.000"))
}
}
HTTP服務(wù)請求限流
當(dāng)我們通過jmeter/腳本/連續(xù)刷新頁面并發(fā)請求測試時(shí),發(fā)現(xiàn)在1s內(nèi),服務(wù)器最多只能處理2個(gè)請求,其余請求都不會(huì)被處理,會(huì)返回Too Many Requests。
// Demo_CurrentHandleWithHTTP 模擬HTTP請求限流
func Demo_CurrentHandleWithHTTP() {
// 每秒最多處理 1 個(gè)請求,允許突發(fā) 2 個(gè)請求
limiter := rate.NewLimiter(1, 2)
http.HandleFunc("/", func(w http.ResponseWriter, request *http.Request) {
if limiter.Allow() {
fmt.Fprintln(w, "Request allowed")
} else {
http.Error(w, "Too Many Requests", http.StatusTooManyRequests)
}
})
fmt.Println("Server started at :8080")
_ = http.ListenAndServe(":8080", nil)
}
正常請求:

頻繁請求(超過頻次):

模擬等待耗時(shí)任務(wù)處理
可用于限制資源(文件)的訪問,避免資源(文件)被頻繁訪問造成性能問題。
func Demo_HandleWorkWithWait() {
// 創(chuàng)建一個(gè)限速器,每3秒允許1個(gè)事件
limiter := rate.NewLimiter(rate.Every(3*time.Second), 1)
// 模擬10次對資源的訪問
for i := 0; i < 10; i++ {
// 使用limiter.Wait(ctx)等待,直到可以訪問資源(訪問文件/執(zhí)行數(shù)據(jù)庫查詢等)
if err := limiter.Wait(context.Background()); err != nil {
log.Fatalf("Failed to wait for rate limiter: %v", err)
}
// 訪問資源
fmt.Printf("Accessing resource at %v\n", time.Now())
}
}
全部代碼
Github:https://github.com/ziyifast/ziyifast-code_instruction/tree/main/go-demo/go-rat
參考文章:
https://cloud.tencent.com/developer/article/2429254
https://www.cnblogs.com/gnivor/p/10623028.html
到此這篇關(guān)于go rate 原生標(biāo)準(zhǔn)限速庫的使用的文章就介紹到這了,更多相關(guān)go rate 原生標(biāo)準(zhǔn)限速庫內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang信號(hào)量設(shè)計(jì)實(shí)現(xiàn)示例詳解
這篇文章主要為大家介紹了Golang信號(hào)量設(shè)計(jì)實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
Golang中基于HTTP協(xié)議的網(wǎng)絡(luò)服務(wù)
HTTP協(xié)議是基于TCP/IP協(xié)議棧的,并且它也是一個(gè)面向普通文本的協(xié)議。這篇文章主要詳細(xì)介紹了Golang中基于HTTP協(xié)議的網(wǎng)絡(luò)服務(wù),感興趣的小伙伴可以借鑒一下2023-04-04
深入了解Golang中的Slice底層實(shí)現(xiàn)
本文主要為大家詳細(xì)介紹了Golang中slice的底層實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2023-02-02
Golang中匿名組合實(shí)現(xiàn)偽繼承的方法
這篇文章主要介紹了Golang中匿名組合實(shí)現(xiàn)偽繼承的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-08-08

