Sentinel

Example

项目地址Sentinel - 图1 (opens new window) 官方文档Sentinel - 图2 (opens new window) ego版本:ego@v0.6.4

Sentinel配置

  1. type Config struct {
  2. AppName string `json:"appName"` // 应用名,默认从ego框架内部获取
  3. LogPath string `json:"logPath"` // 日志路径,默认./logs
  4. FlowRulesFile string `json:"flowRulesFile"` // 限流配置路径
  5. }

Sentinel 限流配置

  1. type Rule struct {
  2. ID string
  3. Resource string // 资源名,默认配置形式为Get./hello
  4. TokenCalculateStrategy TokenCalculateStrategy // 0 Direct,1 WarmUp,2 MemoryAdaptive
  5. ControlBehavior ControlBehavior // 控制行为,0 Reject 请求直接拒绝,1 Throttling 请求限流排队
  6. Threshold float64 // 1s内的QPS域值
  7. RelationStrategy RelationStrategy // 0 CurrentResource 当前资源流控行为
  8. RefResource string
  9. MaxQueueingTimeMs uint32
  10. WarmUpPeriodSec uint32
  11. WarmUpColdFactor uint32
  12. StatIntervalInMs uint32
  13. LowMemUsageThreshold int64
  14. HighMemUsageThreshold int64
  15. MemLowWaterMarkBytes int64
  16. MemHighWaterMarkBytes int64
  17. }

一条流控规则主要由下面几个因素组成,我们可以组合这些元素来实现不同的限流效果:

  • Resource:资源名,即规则的作用目标。
  • TokenCalculateStrategy: 当前流量控制器的Token计算策略。Direct表示直接使用字段 Threshold 作为阈值;WarmUp表示使用预热方式计算Token的阈值。
  • ControlBehavior: 表示流量控制器的控制策略;Reject表示超过阈值直接拒绝,Throttling表示匀速排队。
  • Threshold: 表示流控阈值;如果字段 StatIntervalInMs 是1000(也就是1秒),那么Threshold就表示QPS,流量控制器也就会依据资源的QPS来做流控。
  • RelationStrategy: 调用关系限流策略,CurrentResource表示使用当前规则的resource做流控;AssociatedResource表示使用关联的resource做流控,关联的resource在字段 RefResource 定义;
  • RefResource: 关联的resource;
  • WarmUpPeriodSec: 预热的时间长度,该字段仅仅对 WarmUp 的TokenCalculateStrategy生效;
  • WarmUpColdFactor: 预热的因子,默认是3,该值的设置会影响预热的速度,该字段仅仅对 WarmUp 的TokenCalculateStrategy生效;
  • MaxQueueingTimeMs: 匀速排队的最大等待时间,该字段仅仅对 Throttling ControlBehavior生效;
  • StatIntervalInMs: 规则对应的流量控制器的独立统计结构的统计周期。如果StatIntervalInMs是1000,也就是统计QPS。

HTTP限流

配置

  1. [server.http]
  2. host = "0.0.0.0"
  3. port = 9007
  4. enableAccessInterceptorReq = true
  5. enableAccessInterceptorRes = true
  6. enableSentinel = true # 打开限流配置开关
  7. [server.governor]
  8. host = "0.0.0.0"
  9. port = 9003
  10. [sentinel]
  11. flowRulesFile = "./config/sentinel.json" # 设置限流配置路径

限流配置

设置资源名GET./hello1s请求为2个

  1. [
  2. {
  3. "resource": "GET./hello",
  4. "threshold": 2,
  5. "tokenCalculateStrategy": 0,
  6. "controlBehavior": 0
  7. }
  8. ]

启动服务

  1. package main
  2. import (
  3. "github.com/gin-gonic/gin"
  4. "github.com/gotomicro/ego"
  5. "github.com/gotomicro/ego/core/elog"
  6. "github.com/gotomicro/ego/server/egin"
  7. "github.com/gotomicro/ego/server/egovernor"
  8. )
  9. // export EGO_DEBUG=true && go run main.go
  10. // ab -n 10 -c 10 http://127.0.0.1:9007/hello,可以看到429,说明限流
  11. func main() {
  12. if err := ego.New().Serve(func() *egin.Component {
  13. server := egin.Load("server.http").Build()
  14. server.GET("/hello", func(c *gin.Context) {
  15. c.JSON(200, "Hello EGO")
  16. return
  17. })
  18. return server
  19. }(),
  20. egovernor.Load("server.governor").Build(),
  21. ).Run(); err != nil {
  22. elog.Panic("startup", elog.FieldErr(err))
  23. }
  24. }

测试限流

  1. ab -n 10 -c 10 http://127.0.0.1:9007/hello

img.png 可以看到按照sentinel的限流指标只通过了2条请求,其余请求全部拒绝,状态码响应429

测试监控数据

  1. curl http://127.0.0.1:9003/metics

img.png 官方监控还不全,后续等官方新的PR https://github.com/alibaba/sentinel-golang/pull/382合并后,可以看到更完整限流监控

动态修改限流参数

更改sentinel.json里的thresholdego会实时监听,并更新限流数据,同时prometheus监控数据都会做相应更改 img.png

限流可选参数

如果想自定义资源名或者自定义限流的错误码信息,可以使用egin里的options参数。

  1. func main() {
  2. if err := ego.New().Serve(func() *egin.Component {
  3. server := egin.Load("server.http").Build(
  4. egin.WithSentinelResourceExtractor(func(ctx *gin.Context) string {
  5. return ctx.Request.Method + "." + ctx.FullPath()
  6. }),
  7. egin.WithSentinelBlockFallback(func(ctx *gin.Context) {
  8. ctx.AbortWithStatusJSON(429, gin.H{"msg": "too many requests"})
  9. }),
  10. )
  11. server.GET("/hello", func(c *gin.Context) {
  12. c.JSON(200, "Hello EGO")
  13. return
  14. })
  15. return server
  16. }(),
  17. egovernor.Load("server.governor").Build(),
  18. ).Run(); err != nil {
  19. elog.Panic("startup", elog.FieldErr(err))
  20. }
  21. }