这是我参与8月更文挑战的第25天,活动详情查看:8月更文挑战
如果❤️我的文章有帮助,欢迎点赞、关注。这是对我继续技术创作最大的鼓励。更多往期文章在我的个人专栏
系统限流的意义 & Golang 代码实现
限流的意义
高并发系统三大利器:缓存、降级、限流
- 缓存:提升系统访问速度和增大处理容量,为相应业务增加缓存。
- 降级:当服务器压力剧增时,根据业务策略降级,以此释放服务资源保证业务正常。
- 限流:通过对并发限速,达到拒绝服务、排队、等候、降级等处理
漏桶限流 time/rate
- rate.NewLimiter(limit,burst)
- limit表示每秒产生token数、burst最多存token数
- Allow判断当前是否可以取到token
- Wait阻塞等待直到取到token
- Reserve返回等待时间,再去取token
time/rate 源代码窥探
- 计算上次请求和当前请求时间差
- 计算时间差内生成的token数+旧token数
- 如果token为负,计算等待时间
- token为正,则请求后token-1
给网关代理插上限流的翅膀
package middleware
import (
"fmt"
"golang.org/x/time/rate"
)
func RateLimiter() func(c *SliceRouterContext) {
l := rate.NewLimiter(1, 2)
return func(c *SliceRouterContext) {
if !l.Allow() {
c.Rw.Write([]byte(fmt.Sprintf("rate limit:%v,%v", l.Limit(), l.Burst())))
c.Abort()
return
}
c.Next()
}
}
接入到中间件
package main
import (
"github.com/e421083458/gateway_demo/proxy/middleware"
"github.com/e421083458/gateway_demo/proxy/proxy"
"log"
"net/http"
"net/url"
)
var addr = "127.0.0.1:2002"
// 熔断方案
func main() {
coreFunc := func(c *middleware.SliceRouterContext) http.Handler {
rs1 := "http://127.0.0.1:2003/base"
url1, err1 := url.Parse(rs1)
if err1 != nil {
log.Println(err1)
}
rs2 := "http://127.0.0.1:2004/base"
url2, err2 := url.Parse(rs2)
if err2 != nil {
log.Println(err2)
}
urls := []*url.URL{url1, url2}
return proxy.NewMultipleHostsReverseProxy(c, urls)
}
log.Println("Starting httpserver at " + addr)
sliceRouter := middleware.NewSliceRouter()
sliceRouter.Group("/").Use(middleware.RateLimiter())
routerHandler := middleware.NewSliceRouterHandler(coreFunc, sliceRouter)
log.Fatal(http.ListenAndServe(addr, routerHandler))
}
测试
$ curl '127.0.0.1:2002/abo'
http://127.0.0.1:2004/base/abo
RemoteAddr=127.0.0.1:62366,X-Forwarded-For=127.0.0.1,X-Real-Ip=
headers =map[Accept:[*/*] Accept-Encoding:[gzip] User-Agent:[curl/7.69.1] X-Forwarded-For:[127.0.0.1]]
Administrator@DESKTOP-U15QB8I MINGW64 /d/Dev/workplace/golang/gateway_v1/pratise/proxy/limiter/rate_limiter (master)
$ curl '127.0.0.1:2002/abo'
rate limit:1,2
Administrator@DESKTOP-U15QB8I MINGW64 /d/Dev/workplace/golang/gateway_v1/pratise/proxy/limiter/rate_limiter (master)
$ curl '127.0.0.1:2002/abo'
http://127.0.0.1:2004/base/abo
RemoteAddr=127.0.0.1:62366,X-Forwarded-For=127.0.0.1,X-Real-Ip=
headers =map[Accept:[*/*] Accept-Encoding:[gzip] User-Agent:[curl/7.69.1] X-Forwarded-For:[127.0.0.1]]
Administrator@DESKTOP-U15QB8I MINGW64 /d/Dev/workplace/golang/gateway_v1/pratise/proxy/limiter/rate_limiter (master)
$ curl '127.0.0.1:2002/abo'
rate limit:1,2