go基于Gin框架的HTTP接口限速实践
作者:海风极客
在当今的微服务架构和RESTful API主导的时代,HTTP接口在各个业务模块之间扮演着重要的角色。随着业务规模的不断扩大,接口的访问频率和负载也随之增加。为了确保系统的稳定性和性能,接口限速成了一个重要的话题。
1 接口限速的使用场景
接口限速的使用场景主要涉及以下几种情况:
- 防止API滥用:在某些情况下,如果没有有效的限速机制,恶意用户可能会无限制地调用API,导致系统过载。通过接口限速,我们可以限制每个用户对特定接口的访问频率,从而防止API滥用。
- 保护服务稳定性:在某些情况下,某些高频调用可能会给后端服务带来巨大的压力,影响服务的稳定性和性能。通过接口限速,我们可以限制对这些接口的访问频率,从而保护服务的稳定性。
- 资源合理分配:在一些情况下,我们需要对系统资源进行合理的分配,确保每个用户都能得到公平的资源使用。通过接口限速,我们可以根据用户的请求频率进行资源分配,从而保证公平性。
2 限速不同与限流
接口限速和限流是两个不同的概念,虽然它们都是用来控制流量和保护系统的手段,但它们的目的和实现方式有所不同。
接口限速主要是限制接口的访问速度,避免过快的请求频率对系统造成压力。它关注的是单个接口的访问速率,比如每秒可以访问多少次,而限流则是关注系统的整体流量,限制单位时间内系统的总访问量。
限速通常是通过在接口上设置速率限制来实现的,例如使用令牌桶算法或漏桶算法等。它的主要目的是防止单个接口的过快访问,以保护系统的稳定性和性能。
而限流则是通过一系列机制来限制单位时间内系统的总访问量,以防止系统过载。常见的限流算法包括令牌桶算法、漏桶算法和热点参数等。它的主要目的是保护整个系统,避免因为访问量过大而出现崩溃或性能下降的情况。
在实现方面,限速通常是在应用程序或API网关层面实现的,而限流则可能需要涉及到整个系统的架构和设计。
虽然接口限速和限流的目的和实现方式有所不同,但它们都是为了控制流量和保护系统的稳定性和性能。在实际应用中,我们可以根据实际情况选择合适的限速和限流策略,以实现最佳的流量控制效果。
3 Gin框架接口限速实践
基于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...") }
返回结果:
3.3 不同接口区分速率
我们假设系统有两个接口:
- /fast : 每分钟允许10次访问
- /slow : 每分钟允许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" ) 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 小总结
接口限速是保护系统稳定性和API的重要手段。在实际应用中,我们需要根据实际情况选择合适的限速方法,实现对接口的全面限速。通过接口限速,我们可以提高系统的稳定性、保护API、提高用户体验等。
到此这篇关于go基于Gin框架的HTTP接口限速实践的文章就介绍到这了,更多相关Gin HTTP接口限速内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!