go基于Gin框架的HTTP接口限速實(shí)踐
在當(dāng)今的微服務(wù)架構(gòu)和RESTful API主導(dǎo)的時(shí)代,HTTP接口在各個(gè)業(yè)務(wù)模塊之間扮演著重要的角色。隨著業(yè)務(wù)規(guī)模的不斷擴(kuò)大,接口的訪問(wèn)頻率和負(fù)載也隨之增加。為了確保系統(tǒng)的穩(wěn)定性和性能,接口限速成了一個(gè)重要的話題。
1 接口限速的使用場(chǎng)景
接口限速的使用場(chǎng)景主要涉及以下幾種情況:
- 防止API濫用:在某些情況下,如果沒有有效的限速機(jī)制,惡意用戶可能會(huì)無(wú)限制地調(diào)用API,導(dǎo)致系統(tǒng)過(guò)載。通過(guò)接口限速,我們可以限制每個(gè)用戶對(duì)特定接口的訪問(wèn)頻率,從而防止API濫用。
- 保護(hù)服務(wù)穩(wěn)定性:在某些情況下,某些高頻調(diào)用可能會(huì)給后端服務(wù)帶來(lái)巨大的壓力,影響服務(wù)的穩(wěn)定性和性能。通過(guò)接口限速,我們可以限制對(duì)這些接口的訪問(wèn)頻率,從而保護(hù)服務(wù)的穩(wěn)定性。
- 資源合理分配:在一些情況下,我們需要對(duì)系統(tǒng)資源進(jìn)行合理的分配,確保每個(gè)用戶都能得到公平的資源使用。通過(guò)接口限速,我們可以根據(jù)用戶的請(qǐng)求頻率進(jìn)行資源分配,從而保證公平性。
2 限速不同與限流
接口限速和限流是兩個(gè)不同的概念,雖然它們都是用來(lái)控制流量和保護(hù)系統(tǒng)的手段,但它們的目的和實(shí)現(xiàn)方式有所不同。
接口限速主要是限制接口的訪問(wèn)速度,避免過(guò)快的請(qǐng)求頻率對(duì)系統(tǒng)造成壓力。它關(guān)注的是單個(gè)接口的訪問(wèn)速率,比如每秒可以訪問(wèn)多少次,而限流則是關(guān)注系統(tǒng)的整體流量,限制單位時(shí)間內(nèi)系統(tǒng)的總訪問(wèn)量。
限速通常是通過(guò)在接口上設(shè)置速率限制來(lái)實(shí)現(xiàn)的,例如使用令牌桶算法或漏桶算法等。它的主要目的是防止單個(gè)接口的過(guò)快訪問(wèn),以保護(hù)系統(tǒng)的穩(wěn)定性和性能。
而限流則是通過(guò)一系列機(jī)制來(lái)限制單位時(shí)間內(nèi)系統(tǒng)的總訪問(wèn)量,以防止系統(tǒng)過(guò)載。常見的限流算法包括令牌桶算法、漏桶算法和熱點(diǎn)參數(shù)等。它的主要目的是保護(hù)整個(gè)系統(tǒng),避免因?yàn)樵L問(wèn)量過(guò)大而出現(xiàn)崩潰或性能下降的情況。
在實(shí)現(xiàn)方面,限速通常是在應(yīng)用程序或API網(wǎng)關(guān)層面實(shí)現(xiàn)的,而限流則可能需要涉及到整個(gè)系統(tǒng)的架構(gòu)和設(shè)計(jì)。
雖然接口限速和限流的目的和實(shí)現(xiàn)方式有所不同,但它們都是為了控制流量和保護(hù)系統(tǒng)的穩(wěn)定性和性能。在實(shí)際應(yīng)用中,我們可以根據(jù)實(shí)際情況選擇合適的限速和限流策略,以實(shí)現(xiàn)最佳的流量控制效果。
3 Gin框架接口限速實(shí)踐
基于limiter插件的GitHub地址:github.com/ulule/limiter
3.1 基本使用
package main import ( "fmt" "log" "net/http" "github.com/gin-gonic/gin" "github.com/redis/go-redis/v9" "github.com/ulule/limiter/v3" mgin "github.com/ulule/limiter/v3/drivers/middleware/gin" sredis "github.com/ulule/limiter/v3/drivers/store/redis" ) func main() { // Define a limit rate to 4 requests per hour. rate, err := limiter.NewRateFromFormatted("4-M") if err != nil { log.Fatal(err) return } // Create a redis client. option, err := redis.ParseURL("redis://localhost:6379/0") if err != nil { log.Fatal(err) return } client := redis.NewClient(option) // Create a store with the redis client. store, err := sredis.NewStoreWithOptions(client, limiter.StoreOptions{ Prefix: "limiter_gin_example", MaxRetry: 3, }) if err != nil { log.Fatal(err) return } // Create a new middleware with the limiter instance. middleware := mgin.NewMiddleware(limiter.New(store, rate)) // Launch a simple server. router := gin.Default() router.ForwardedByClientIP = true router.Use(middleware) router.GET("/", index) log.Fatal(router.Run(":8081")) } func index(c *gin.Context) { c.JSON(http.StatusOK, "This is my gin api...") }
3.2 引入自定義攔截處理器
package main import ( "fmt" "log" "net/http" "github.com/gin-gonic/gin" "github.com/redis/go-redis/v9" "github.com/ulule/limiter/v3" mgin "github.com/ulule/limiter/v3/drivers/middleware/gin" sredis "github.com/ulule/limiter/v3/drivers/store/redis" ) func main() { rate, err := limiter.NewRateFromFormatted("4-M") if err != nil { log.Fatal(err) return } option, err := redis.ParseURL("redis://localhost:6379/0") if err != nil { log.Fatal(err) return } client := redis.NewClient(option) store, err := sredis.NewStoreWithOptions(client, limiter.StoreOptions{ Prefix: "limiter_gin_example", MaxRetry: 3, }) if err != nil { log.Fatal(err) return } //自定義攔截處理器 opt := mgin.WithLimitReachedHandler(ExceededHandler) middleware := mgin.NewMiddleware(limiter.New(store, rate), opt) router := gin.Default() router.ForwardedByClientIP = true router.Use(middleware) router.GET("/", index) log.Fatal(router.Run(":8081")) } func ExceededHandler(c *gin.Context) { c.JSON(200, "This is mu custom ExceededHandler...") } func index(c *gin.Context) { c.JSON(http.StatusOK, "This is my gin api...") }
返回結(jié)果:
3.3 不同接口區(qū)分速率
我們假設(shè)系統(tǒng)有兩個(gè)接口:
- /fast : 每分鐘允許10次訪問(wèn)
- /slow : 每分鐘允許1次訪問(wèn)
代碼實(shí)現(xiàn):
package main import ( "fmt" "log" "net/http" "github.com/gin-gonic/gin" "github.com/redis/go-redis/v9" "github.com/ulule/limiter/v3" mgin "github.com/ulule/limiter/v3/drivers/middleware/gin" sredis "github.com/ulule/limiter/v3/drivers/store/redis" ) var ( fastTime = 0 slowTime = 0 ) func FastApi(c *gin.Context) { fastTime += 1 c.JSON(200, fmt.Sprintf("This is fast api... %d", fastTime)) } func SlowApi(c *gin.Context) { slowTime += 1 c.JSON(200, fmt.Sprintf("This is slow api... %d", slowTime)) } func main() { fastRate, err := limiter.NewRateFromFormatted("10-M") if err != nil { log.Fatal(err) return } slowRate, err := limiter.NewRateFromFormatted("1-M") if err != nil { log.Fatal(err) return } option, err := redis.ParseURL("redis://localhost:6379/0") if err != nil { log.Fatal(err) return } client := redis.NewClient(option) storeFast, err := sredis.NewStoreWithOptions(client, limiter.StoreOptions{Prefix: "limiter_gin_example_fast", MaxRetry: 3}) if err != nil { log.Fatal(err) return } storeSlow, err := sredis.NewStoreWithOptions(client, limiter.StoreOptions{Prefix: "limiter_gin_example_slow", MaxRetry: 3}) if err != nil { log.Fatal(err) return } //自定義攔截處理器 opt := mgin.WithLimitReachedHandler(ExceededHandler) middlewareFast := mgin.NewMiddleware(limiter.New(storeFast, fastRate), opt) middlewareSlow := mgin.NewMiddleware(limiter.New(storeSlow, slowRate), opt) router := gin.Default() router.ForwardedByClientIP = true router.Use(func(c *gin.Context) { if c.Request.RequestURI == "/fast" { middlewareFast(c) return } if c.Request.RequestURI == "/slow" { middlewareSlow(c) return } }) router.GET("/fast", FastApi) router.GET("/slow", SlowApi) log.Fatal(router.Run(":8081")) } func ExceededHandler(c *gin.Context) { c.JSON(200, "This is mu custom ExceededHandler...") }
4 小總結(jié)
接口限速是保護(hù)系統(tǒng)穩(wěn)定性和API的重要手段。在實(shí)際應(yīng)用中,我們需要根據(jù)實(shí)際情況選擇合適的限速方法,實(shí)現(xiàn)對(duì)接口的全面限速。通過(guò)接口限速,我們可以提高系統(tǒng)的穩(wěn)定性、保護(hù)API、提高用戶體驗(yàn)等。
到此這篇關(guān)于go基于Gin框架的HTTP接口限速實(shí)踐的文章就介紹到這了,更多相關(guān)Gin HTTP接口限速內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang?db事務(wù)的統(tǒng)一封裝的實(shí)現(xiàn)
這篇文章主要介紹了golang db事務(wù)的統(tǒng)一封裝的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12Golang?基于flag庫(kù)實(shí)現(xiàn)一個(gè)簡(jiǎn)單命令行工具
這篇文章主要介紹了Golang基于flag庫(kù)實(shí)現(xiàn)一個(gè)簡(jiǎn)單命令行工具,Golang標(biāo)準(zhǔn)庫(kù)中的flag庫(kù)提供了解析命令行選項(xiàng)的能力,我們可以基于此來(lái)開發(fā)命令行工具,下文詳細(xì)介紹。需要的小伙伴可以參考一下2022-08-08golang實(shí)現(xiàn)微信小程序商城后臺(tái)系統(tǒng)(moshopserver)
這篇文章主要介紹了golang實(shí)現(xiàn)微信小程序商城后臺(tái)系統(tǒng)(moshopserver),本文通過(guò)截圖實(shí)例代碼的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02Golang的循環(huán)語(yǔ)句和循環(huán)控制語(yǔ)句詳解
循環(huán)語(yǔ)句為了簡(jiǎn)化程序中有規(guī)律的重復(fù)性操作,需要用到循環(huán)語(yǔ)句,和其他大多數(shù)編程語(yǔ)言一樣,GO的循環(huán)語(yǔ)句有for循環(huán),不同的是沒有while循環(huán),而循環(huán)控制語(yǔ)句可以改變循環(huán)語(yǔ)句的執(zhí)行過(guò)程,下面給大家介紹下go循環(huán)語(yǔ)句和循環(huán)控制語(yǔ)句的相關(guān)知識(shí),一起看看吧2021-11-11