Description
Issue Description
Type: feature request
Describe what feature you want
Current feature
Now the definition of flow.Rule is as below:
type Rule struct {
// ID represents the unique ID of the rule (optional).
ID string `json:"id,omitempty"`
// Resource represents the resource name.
Resource string `json:"resource"`
TokenCalculateStrategy TokenCalculateStrategy `json:"tokenCalculateStrategy"`
ControlBehavior ControlBehavior `json:"controlBehavior"`
// Threshold means the threshold during StatIntervalInMs
// If StatIntervalInMs is 1000(1 second), Threshold means QPS
Threshold float64 `json:"threshold"`
RelationStrategy RelationStrategy `json:"relationStrategy"`
RefResource string `json:"refResource"`
MaxQueueingTimeMs uint32 `json:"maxQueueingTimeMs"`
WarmUpPeriodSec uint32 `json:"warmUpPeriodSec"`
WarmUpColdFactor uint32 `json:"warmUpColdFactor"`
// StatIntervalInMs indicates the statistic interval and it's the optional setting for flow Rule.
// If user doesn't set StatIntervalInMs, that means using default metric statistic of resource.
// If the StatIntervalInMs user specifies can not reuse the global statistic of resource,
// sentinel will generate independent statistic structure for this rule.
StatIntervalInMs uint32 `json:"statIntervalInMs"`
}
As the doc 流量控制 describes:
这里特别强调一下StatIntervalInMs和Threshold这两个字段,这两个字段决定了流量控制器的灵敏度。以 Direct + Reject 的流控策略为例,流量控制器的行为就是在StatIntervalInMs周期内,允许的最大请求数量是Threshold。比如,如果StatIntervalInMs是10000,Threshold是10000,那么流量控制器的行为就是10s内运行最多10000次访问。
But now there is scenario that the total passed requests count in StatIntervalInMs
can exceeds the Threshold
. And this is inconsistent with the doc description.
Example
Now let‘s see an example.
A throttling rule as below:
flow.Rule{
Resource: "some-test",
TokenCalculateStrategy: flow.Direct,
ControlBehavior: flow.Throttling,
Threshold: 10,
StatIntervalInMs: 1000,
}
And we build a request sequence:
time 1.0s: req batch = 10
time 1.1s: req batch = 1
time 1.2s: req batch = 1
time 1.3s: req batch = 1
time 1.4s: req batch = 1
time 1.5s: req batch = 1
time 1.6s: req batch = 1
time 1.7s: req batch = 1
time 1.8s: req batch = 1
time 1.9s: req batch = 1
If we use the latest version of master currently(c40258e), all requests would pass. In one StatIntervalInMs
, there are 19 resource accesses allowed, which exceeds the Threshold
10.
Detail example code:
package main
import (
"fmt"
"log"
"time"
sentinel "github.com/alibaba/sentinel-golang/api"
"github.com/alibaba/sentinel-golang/core/base"
"github.com/alibaba/sentinel-golang/core/config"
"github.com/alibaba/sentinel-golang/core/flow"
"github.com/alibaba/sentinel-golang/logging"
)
func main() {
// We should initialize Sentinel first.
conf := config.NewDefaultConfig()
// for testing, logging output to console
conf.Sentinel.Log.Logger = logging.NewConsoleLogger()
err := sentinel.InitWithConfig(conf)
if err != nil {
log.Fatal(err)
}
_, err = flow.LoadRules([]*flow.Rule{
{
Resource: "some-test",
TokenCalculateStrategy: flow.Direct,
ControlBehavior: flow.Throttling,
Threshold: 10,
StatIntervalInMs: 1000,
},
})
if err != nil {
log.Fatalf("Unexpected error: %+v", err)
return
}
start := time.Now()
time.Sleep(time.Second)
batch := uint32(10)
_, b := sentinel.Entry("some-test", sentinel.WithTrafficType(base.Inbound), sentinel.WithBatchCount(batch))
if b == nil {
fmt.Printf("time: %.2f, batch: %d, result: %s\n", time.Since(start).Seconds(), batch, "pass")
} else {
fmt.Printf("time: %.2f, batch: %d, result: %s\n", time.Since(start).Seconds(), batch, "block")
}
for i := 0; i < 9; i++ {
time.Sleep(time.Millisecond * 100)
batch = 1
_, b := sentinel.Entry("some-test", sentinel.WithTrafficType(base.Inbound), sentinel.WithBatchCount(batch))
if b == nil {
fmt.Printf("time: %.2f, batch: %d, result: %s\n", time.Since(start).Seconds(), batch, "pass")
} else {
fmt.Printf("time: %.2f, batch: %d, result: %s\n", time.Since(start).Seconds(), batch, "block")
}
}
}
Run result:
time: 1.00, batch: 10, result: pass
time: 1.10, batch: 1, result: pass
time: 1.20, batch: 1, result: pass
time: 1.30, batch: 1, result: pass
time: 1.40, batch: 1, result: pass
time: 1.50, batch: 1, result: pass
time: 1.60, batch: 1, result: pass
time: 1.70, batch: 1, result: pass
time: 1.80, batch: 1, result: pass
time: 1.90, batch: 1, result: pass
Need feature
More detail control of throttling is needed. The flow rule now only have Threshold
and StateIntervalMs
to control throttling behavior, which may be not enough, and may cause incorrect usage. Maybe a burst param is needed to control burst traffic.
More discuss is welcomed.
Additional context
Add any other context or screenshots about the feature request here.