写本文的初衷挺简单的,官方文档有些复杂,磕磕碰碰太多,特此记录一下怎么弄。
ps : 官方文档可能太久没更新了,挺多东西跟包里还是有区别的
安装
go get -u github.com/alibaba/sentinel-golang
导入
此处建议配置成一样的,后面比较好 copy (^_^)
import(
sentinel "github.com/alibaba/sentinel-golang/api"
)
Demos
1.流量控制
这是一个简单的 demo ,请自己跑起来试试,并且根据下面的流控规则,理解如何去编写规则。
package main
import (
sentinel "github.com/alibaba/sentinel-golang/api"
"github.com/alibaba/sentinel-golang/core/base"
"github.com/alibaba/sentinel-golang/core/flow"
"github.com/gin-gonic/gin"
)
// Sentinel 中间件
func Sentinel(resource string) gin.HandlerFunc {
return func(c *gin.Context) {
// 通过api.Entry创建一个资源的访问入口,如果资源的访问量超过了限流规则中的阈值,就会返回限流错误
e, b := sentinel.Entry(resource, sentinel.WithTrafficType(base.Inbound))
if b != nil {
c.JSON(429, gin.H{
"err": "too many requests",
})
c.Abort()
return
}
defer e.Exit()
c.Next()
}
}
func main() {
sentinel.InitDefault()
flow.LoadRules([]*flow.Rule{
{
// 资源名称
Resource: "/ping",
TokenCalculateStrategy: flow.Direct,
ControlBehavior: flow.Reject,
Threshold: 1,
StatIntervalInMs: 1000,
RelationStrategy: flow.CurrentResource,
},
})
r := gin.Default()
r.GET("/ping", Sentinel("/ping"), func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run(":8888")
}
2.熔断降级
流量控制
流控规则
下表整理了流量控制的各项配置参数及其描述:
配置参数 | json 标识 | 描述 | 类型 | 示例 | 备注 |
---|---|---|---|---|---|
Resource | resource | 资源名称,示例值为 “/ping” | string | “/ping” | |
TokenCalculateStrategy | tokenCalculateStrategy | Token计算策略: Direct(直接阈值) WarmUp(预热计算) MemoryAdaptive(内存自适应调整) | flow.TokenCalculateStrategy | flow.Direct | |
ControlBehavior | controlBehavior | 流控策略: Reject(直接拒绝) Throttling(匀速排队) | flow.ControlBehavior | flow.Reject | |
Threshold | threshold | 限流阈值,示例中每秒1次请求 | float64 | 100 | |
StatIntervalInMs | statIntervalInMs | 统计时间窗口,单位毫秒,示例中为1000ms | uint32(单位是 ms) | 1000 | |
RelationStrategy | relationStrategy | 调用关系限流策略: CurrentResource(当前资源限流) AssociatedResource(关联资源限流) | flow.RelationStrategy | flow.CurrentResource | 此处主要的使用场景是:存在 A 策略需要占用 B 策略的资源。此时使用此参数(建议一个接口用一个 resource) |
RefResource | refResource | 关联的资源名称,对应AssociatedResource策略 | string | ||
WarmUpPeriodSec | warmUpPeriodSec | 预热时间长度,单位秒,仅WarmUp策略有效 | uint32 | 10 | |
WarmUpColdFactor | warmUpColdFactor | 预热因子,默认为3,影响预热速度,仅WarmUp策略有效 | uint32 | 3 | |
MaxQueueingTimeMs | maxQueueingTimeMs | 匀速排队的最大等待时间,单位毫秒,仅在 ControlBehavior 使用 Throttling 时有效 | uint32 | ||
LowMemUsageThreshold | lowMemUsageThreshold | 低内存使用率阈值,内存使用率低于此值时流控阈值降低,仅 MemoryAdaptive 策略有效 | int64 | ||
HighMemUsageThreshold | highMemUsageThreshold | 高内存使用率阈值,内存使用率高于此值时流控阈值升高,仅 MemoryAdaptive 策略有效 | int64 | ||
MemLowWaterMarkBytes | memLowWaterMarkBytes | 内存使用率低水位,低于此值流控阈值降低,仅 MemoryAdaptive 策略有效 | int64 | ||
MemHighWaterMarkBytes | memHighWaterMarkBytes | 内存使用率高水位,高于此值流控阈值升高,仅 MemoryAdaptive 策略有效 | int64 |
并发隔离控制
系统自适应流控
Sentinel 系统自适应流控从整体维度对应用入口流量进行控制,结合系统的 Load、CPU 使用率以及应用的入口 QPS、平均响应时间和并发量等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统保护规则是应用整体维度的,而不是单个调用维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(埋点的 TrafficType 为 Inbound
),比如 Web 服务或 gRPC provider 接收的请求,都属于入口流量。
规则配置方法如下
import "github.com/alibaba/sentinel-golang/core/system"
func loadSystemRule(){
// 自适应流控,启发因子为 load1 >= 8
_, err := system.LoadRules([]*system.Rule{
{
MetricType: system.Load,
TriggerCount: 8.0,
Strategy: system.BBR,
},
})
}
规则
字段 | 描述 | 类型 | 示例 | 备注 |
---|---|---|---|---|
MetricType | 触发度量的类型: Load:表示Linux/Unix系统的负载(load average) AvgRT:表示所有入站请求的平均响应时间 Concurrency:表示所有入站请求的并发数 InboundQPS:表示所有入站请求的每秒查询率(QPS) CpuUsage:表示系统的CPU使用率百分比 MetricTypeSize:表示 MetricType 枚举的大小,通常用于枚举边界检查 | system.MetricType | system.Load | |
TriggerCount | 自适应策略的触发阈值下限 | float64 | 80.0 | |
Strategy | 自适应策略 | system.AdaptiveStrategy | ReduceRequests |
热点参数流控
熔断降级
动态数据源
本地文件
本方法可以动态监视本地数据规则。
编写 rules.json
[
{
"resource": "/ping",
"tokenCalculateStrategy": 0,
"controlBehavior": 0,
"threshold": 0.0,
"relationStrategy": 0
}
]
package main
import (
"github.com/alibaba/sentinel-golang/ext/datasource"
"github.com/alibaba/sentinel-golang/ext/datasource/file"
)
func loadRulesFromFile(filePath string) error {
// 注册流控规则数据源
// 对于不同的数据去向,再次进行调整
// 此处使用的是规则文件,因此使用的是 FlowRuleJsonArrayParser
h := datasource.NewDefaultPropertyHandler(datasource.FlowRuleJsonArrayParser, datasource.FlowRulesUpdater)
ds := file.NewFileDataSource(filePath, h)
err := ds.Initialize()
if err != nil {
return err
}
src, err := ds.ReadSource()
if err != nil {
return err
}
err = ds.Handle(src)
if err != nil {
return err
}
return nil
}
在主函数中初始化后调用loadRulesFromFile
即可
package main
import (
sentinel "github.com/alibaba/sentinel-golang/api"
"github.com/alibaba/sentinel-golang/core/base"
"github.com/gin-gonic/gin"
)
// Sentinel 中间件
func Sentinel(resource string) gin.HandlerFunc {
return func(c *gin.Context) {
// 通过api.Entry创建一个资源的访问入口,如果资源的访问量超过了限流规则中的阈值,就会返回限流错误
// 此处埋点的是
e, b := sentinel.Entry(resource, sentinel.WithTrafficType(base.Inbound))
if b != nil {
c.JSON(429, gin.H{
"err": "too many requests",
})
c.Abort()
return
}
defer e.Exit()
c.Next()
}
}
func main() {
sentinel.InitDefault()
// 初始化后加载规则
loadRulesFromFile("./rules.json")
//flow.LoadRules([]*flow.Rule{
// {
// // 资源名称
// Resource: "/ping",
// TokenCalculateStrategy: flow.Direct,
// ControlBehavior: flow.Reject,
// Threshold: 1,
// StatIntervalInMs: 1000,
// RelationStrategy: flow.CurrentResource,
// },
//})
r := gin.Default()
r.GET("/ping", Sentinel("/ping"), func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run(":8888")
}
etcd
todo