-
Notifications
You must be signed in to change notification settings - Fork 438
/
Copy pathrule.go
169 lines (149 loc) · 6.38 KB
/
rule.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// Copyright 1999-2020 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package flow
import (
"encoding/json"
"fmt"
"github.com/alibaba/sentinel-golang/util"
)
// RelationStrategy indicates the flow control strategy based on the relation of invocations.
type RelationStrategy int32
const (
// CurrentResource means flow control by current resource directly.
CurrentResource RelationStrategy = iota
// AssociatedResource means flow control by the associated resource rather than current resource.
AssociatedResource
)
func (s RelationStrategy) String() string {
switch s {
case CurrentResource:
return "CurrentResource"
case AssociatedResource:
return "AssociatedResource"
default:
return "Undefined"
}
}
type TokenCalculateStrategy int32
const (
Direct TokenCalculateStrategy = iota
WarmUp
MemoryAdaptive
)
func (s TokenCalculateStrategy) String() string {
switch s {
case Direct:
return "Direct"
case WarmUp:
return "WarmUp"
case MemoryAdaptive:
return "MemoryAdaptive"
default:
return "Undefined"
}
}
// ControlBehavior defines the behavior when requests have reached the capacity of the resource.
type ControlBehavior int32
const (
Reject ControlBehavior = iota
// Throttling indicates that pending requests will be throttled, wait in queue (until free capacity is available)
Throttling
)
func (s ControlBehavior) String() string {
switch s {
case Reject:
return "Reject"
case Throttling:
return "Throttling"
default:
return "Undefined"
}
}
// Rule describes the strategy of flow control, the flow control strategy is based on QPS statistic metric
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 only takes effect when ControlBehavior is Throttling.
// When MaxQueueingTimeMs is 0, it means Throttling only controls interval of requests,
// and requests exceeding the threshold will be rejected directly.
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"`
// adaptive flow control algorithm related parameters
// limitation: LowMemUsageThreshold > HighMemUsageThreshold && MemHighWaterMarkBytes > MemLowWaterMarkBytes
// if the current memory usage is less than or equals to MemLowWaterMarkBytes, threshold == LowMemUsageThreshold
// if the current memory usage is more than or equals to MemHighWaterMarkBytes, threshold == HighMemUsageThreshold
// if the current memory usage is in (MemLowWaterMarkBytes, MemHighWaterMarkBytes), threshold is in (HighMemUsageThreshold, LowMemUsageThreshold)
LowMemUsageThreshold int64 `json:"lowMemUsageThreshold"`
HighMemUsageThreshold int64 `json:"highMemUsageThreshold"`
MemLowWaterMarkBytes int64 `json:"memLowWaterMarkBytes"`
MemHighWaterMarkBytes int64 `json:"memHighWaterMarkBytes"`
}
func (r *Rule) isEqualsTo(newRule *Rule) bool {
if newRule == nil {
return false
}
if !(r.Resource == newRule.Resource && r.RelationStrategy == newRule.RelationStrategy &&
r.RefResource == newRule.RefResource && r.StatIntervalInMs == newRule.StatIntervalInMs &&
r.TokenCalculateStrategy == newRule.TokenCalculateStrategy && r.ControlBehavior == newRule.ControlBehavior &&
util.Float64Equals(r.Threshold, newRule.Threshold) &&
r.MaxQueueingTimeMs == newRule.MaxQueueingTimeMs && r.WarmUpPeriodSec == newRule.WarmUpPeriodSec &&
r.WarmUpColdFactor == newRule.WarmUpColdFactor &&
r.LowMemUsageThreshold == newRule.LowMemUsageThreshold && r.HighMemUsageThreshold == newRule.HighMemUsageThreshold &&
r.MemLowWaterMarkBytes == newRule.MemLowWaterMarkBytes && r.MemHighWaterMarkBytes == newRule.MemHighWaterMarkBytes) {
return false
}
return true
}
func (r *Rule) isStatReusable(newRule *Rule) bool {
if newRule == nil {
return false
}
return r.Resource == newRule.Resource && r.RelationStrategy == newRule.RelationStrategy &&
r.RefResource == newRule.RefResource && r.StatIntervalInMs == newRule.StatIntervalInMs &&
r.needStatistic() && newRule.needStatistic()
}
func (r *Rule) needStatistic() bool {
return r.TokenCalculateStrategy == WarmUp || r.ControlBehavior == Reject
}
func (r *Rule) String() string {
b, err := json.Marshal(r)
if err != nil {
// Return the fallback string
return fmt.Sprintf("Rule{Resource=%s, TokenCalculateStrategy=%s, ControlBehavior=%s, "+
"Threshold=%.2f, RelationStrategy=%s, RefResource=%s, MaxQueueingTimeMs=%d, WarmUpPeriodSec=%d, WarmUpColdFactor=%d, StatIntervalInMs=%d, "+
"LowMemUsageThreshold=%v, HighMemUsageThreshold=%v, MemLowWaterMarkBytes=%v, MemHighWaterMarkBytes=%v}",
r.Resource, r.TokenCalculateStrategy, r.ControlBehavior, r.Threshold, r.RelationStrategy, r.RefResource,
r.MaxQueueingTimeMs, r.WarmUpPeriodSec, r.WarmUpColdFactor, r.StatIntervalInMs,
r.LowMemUsageThreshold, r.HighMemUsageThreshold, r.MemLowWaterMarkBytes, r.MemHighWaterMarkBytes)
}
return string(b)
}
func (r *Rule) ResourceName() string {
return r.Resource
}