• 基于Gin框架的HTTP接口限速实践


    在当今的微服务架构和RESTful API主导的时代,HTTP接口在各个业务模块之间扮演着重要的角色。随着业务规模的不断扩大,接口的访问频率和负载也随之增加。为了确保系统的稳定性和性能,接口限速成了一个重要的话题。

    1 接口限速的使用场景

    接口限速的使用场景主要涉及以下几种情况:

    1. 防止API滥用:在某些情况下,如果没有有效的限速机制,恶意用户可能会无限制地调用API,导致系统过载。通过接口限速,我们可以限制每个用户对特定接口的访问频率,从而防止API滥用。
    2. 保护服务稳定性:在某些情况下,某些高频调用可能会给后端服务带来巨大的压力,影响服务的稳定性和性能。通过接口限速,我们可以限制对这些接口的访问频率,从而保护服务的稳定性。
    3. 资源合理分配:在一些情况下,我们需要对系统资源进行合理的分配,确保每个用户都能得到公平的资源使用。通过接口限速,我们可以根据用户的请求频率进行资源分配,从而保证公平性。

    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...")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    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...")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    返回结果:

    在这里插入图片描述

    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...")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84

    4 小总结

    接口限速是保护系统稳定性和API的重要手段。在实际应用中,我们需要根据实际情况选择合适的限速方法,实现对接口的全面限速。通过接口限速,我们可以提高系统的稳定性、保护API、提高用户体验等。

  • 相关阅读:
    NLP(15)-序列标注任务
    [附源码]SSM计算机毕业设计郑工校园二手交易平台网站JAVA
    数据库基础面试第二弹
    JDBC封装查询单个和查询多个
    useWindowPrint 自定义的打印HOOK
    Docker容器管理
    【DP】Block Sequence—CF1881E
    【安全利器SELinux快速入门系列】SELINUX配置Proftpd安全FTP服务器权限实操指南
    计算机毕业设计Python+django网上咖啡商城(源码+系统+mysql数据库+Lw文档)
    MIMO信道的随机性
  • 原文地址:https://blog.csdn.net/Mr_YanMingXin/article/details/132640116