什么是限流
限流是指经过必定的算法,对接口的恳求进行约束,防止并发量过大,导致体系瘫痪或响应变慢的状况出现。
为什么要进行限流
在高并发的场景下,假如不进行限流,体系可能会由于过多的恳求而溃散。限流能够维护体系免于被流量打崩,从而保证体系的可用性和稳定性。
Gin结构的限流完成
Gin 是一个根据 Go 言语的 web 结构,它供给了很多便利的中间件,能够便利地完成限流。
以下是一个根据 Gin 完成的令牌桶限流的例子:
-
定义令牌桶结构体
Copy code type TokenBucket struct { capacity int64 // 桶的容量 rate float64 // 令牌放入速率 tokens float64 // 当前令牌数量 lastToken time.Time // 上一次放令牌的时刻 mtx sync.Mutex // 互斥锁 }
-
完成令牌桶算法
func (tb *TokenBucket) Allow() bool { tb.mtx.Lock() defer tb.mtx.Unlock() now := time.Now() // 计算需求放的令牌数量 tb.tokens = tb.tokens + tb.rate*now.Sub(tb.lastToken).Seconds() if tb.tokens > float64(tb.capacity) { tb.tokens = float64(tb.capacity) } // 判断是否答应恳求 if tb.tokens >= 1 { tb.tokens-- tb.lastToken = now return true } else { return false } }
-
运用中间件进行限流
func LimitHandler(maxConn int) gin.HandlerFunc { tb := &TokenBucket{ capacity: maxConn, rate: 1.0, tokens: 0, lastToken: time.Now(), } return func(c *gin.Context) { if !tb.Allow() { c.String(503, "Too many request") c.Abort() return } c.Next() } }
-
在路由中运用中间件
r := gin.Default() // 在路由中运用中间件 r.Use(LimitHandler(100)) r.GET("/", func(c *gin.Context) { c.String(200, "Hello, World!") }) r.Run(":8080")
以上代码完成了一个简略的令牌桶限流中间件,能够约束最大并发连接数为 100。假如超过了这个连接数,将会回来 503 状态码。
测验
浏览器地址栏输入http://localhost:8080/
, 然后张狂刷新即可.
- 测验截图
总结
总的来说,运用 Gin 结构进行限流是一个便利有效的方法,能够进步体系的可用性和稳定性,防止由于过多的恳求导致体系溃散的问题。运用令牌桶算法完成限流能够很好地控制恳求的并发量,能够经过控制桶容量和放入速率等参数进行调理和优化。在运用中间件进行限流时,应该根据实际应用场景和需求调理限流参数,祝您的应用愉快运行!
完整代码
package main
import (
"github.com/gin-gonic/gin"
"sync"
"time"
)
type TokenBucket struct {
capacity int64 // 桶的容量
rate float64 // 令牌放入速率
tokens float64 // 当前令牌数量
lastToken time.Time // 上一次放令牌的时刻
mtx sync.Mutex // 互斥锁
}
func (tb *TokenBucket) Allow() bool {
tb.mtx.Lock()
defer tb.mtx.Unlock()
now := time.Now()
// 计算需求放的令牌数量
tb.tokens = tb.tokens + tb.rate*now.Sub(tb.lastToken).Seconds()
if tb.tokens > float64(tb.capacity) {
tb.tokens = float64(tb.capacity)
}
// 判断是否答应恳求
if tb.tokens >= 1 {
tb.tokens--
tb.lastToken = now
return true
} else {
return false
}
}
func LimitHandler(maxConn int64) gin.HandlerFunc {
tb := &TokenBucket{
capacity: maxConn,
rate: 1.0,
tokens: 0,
lastToken: time.Now(),
}
return func(c *gin.Context) {
if !tb.Allow() {
c.String(503, "Too many request")
c.Abort()
return
}
c.Next()
}
}
func main() {
r := gin.Default()
// 在路由中运用中间件
r.Use(LimitHandler(100))
r.GET("/", func(c *gin.Context) {
c.String(200, "Hello, World!")
})
r.Run(":8080")
}