在生产环境中,我们要确保服务器的稳定的执行,cpu,内存,磁盘等资源能不超过一定量,尤其是对io密集型的服务接口更甚,因为很容易拖垮服务器。我们之前有个服务器就是容易爆,后来使用了限流,就保证了服务器能稳定运行。
go-water框架内置了限流,只需在需要限流的接口对应的服务定义时添加即可,例如:一分钟最多5次
超过流量将报错
water.ServerErrorLimiter(time.Minute, 5)
超过流量将等待加载
water.ServerDelayLimiter(time.Minute, 5)
package main
import (
"context"
"fmt"
"net/http"
"time"
"github.com/go-water/water"
)
func main() {
router := water.New()
router.POST("/", Index)
router.Run(":80")
}
// 控制层
var (
// 超过频次就报错
options = []water.ServerOption{water.ServerErrorLimiter(time.Minute, 5)}
index = water.NewHandler(&IndexService{ServerBase: &water.ServerBase{}}, options...)
)
func Index(ctx *water.Context) {
request, err := water.BindJSON[IndexRequest](ctx)
if err != nil {
ctx.JSON(http.StatusBadRequest, water.H{"err": "binding failure"})
return
}
resp, err := index.ServerWater(ctx, request)
if err != nil {
ctx.JSON(http.StatusBadRequest, water.H{"err": err.Error()})
return
}
ctx.JSON(http.StatusOK, resp)
}
// 业务服务层
type IndexService struct {
*water.ServerBase
}
type IndexRequest struct {
Name string `form:"name"`
}
type IndexResponse struct {
Message string
}
func (s *IndexService) Handle(ctx context.Context, req *IndexRequest) (interface{}, error) {
resp := new(IndexResponse)
resp.Message = fmt.Sprintf("Hello, %s!", req.Name)
return resp, nil
}
测试
--request:
{
"name": "Jimmy"
}
--response:
{
"Message": "Hello, Jimmy!"
}
--多请求几次就变成,按代码配置,请求6次就会返回如下
{
"err": "rate limit exceeded"
}
如果要使用超过频次就延迟,修改如下,仅仅替代一行代码
//options = []water.ServerOption{water.ServerDelayLimiter(time.Minute, 5)}