forked from alibaba/sentinel-golang
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rule.go
134 lines (122 loc) · 5.19 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
// 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 hotspot
import (
"encoding/json"
"fmt"
"reflect"
"strconv"
)
// ControlBehavior indicates the traffic shaping behaviour.
type ControlBehavior int32
const (
Reject ControlBehavior = iota
Throttling
)
func (t ControlBehavior) String() string {
switch t {
case Reject:
return "Reject"
case Throttling:
return "Throttling"
default:
return strconv.Itoa(int(t))
}
}
// MetricType represents the target metric type.
type MetricType int32
const (
// Concurrency represents concurrency count.
Concurrency MetricType = iota
// QPS represents request count per second.
QPS
)
func (t MetricType) String() string {
switch t {
case Concurrency:
return "Concurrency"
case QPS:
return "QPS"
default:
return "Undefined"
}
}
// Rule represents the hotspot(frequent) parameter flow control rule
type Rule struct {
// ID is the unique id
ID string `json:"id,omitempty"`
// Resource is the resource name
Resource string `json:"resource"`
// MetricType indicates the metric type for checking logic.
// For Concurrency metric, hotspot module will check the each hot parameter's concurrency,
// if concurrency exceeds the Threshold, reject the traffic directly.
// For QPS metric, hotspot module will check the each hot parameter's QPS,
// the ControlBehavior decides the behavior of traffic shaping controller
MetricType MetricType `json:"metricType"`
// ControlBehavior indicates the traffic shaping behaviour.
// ControlBehavior only takes effect when MetricType is QPS
ControlBehavior ControlBehavior `json:"controlBehavior"`
// ParamIndex is the index in context arguments slice.
// if ParamIndex is great than or equals to zero, ParamIndex means the <ParamIndex>-th parameter
// if ParamIndex is the negative, ParamIndex means the reversed <ParamIndex>-th parameter
ParamIndex int `json:"paramIndex"`
// ParamKey is the key in EntryContext.Input.Attachments map.
// ParamKey can be used as a supplement to ParamIndex to facilitate rules to quickly obtain parameter from a large number of parameters
// ParamKey is mutually exclusive with ParamIndex, ParamKey has the higher priority than ParamIndex
ParamKey string `json:"paramKey"`
// Threshold is the threshold to trigger rejection
Threshold int64 `json:"threshold"`
// MaxQueueingTimeMs only takes effect when ControlBehavior is Throttling and MetricType is QPS
MaxQueueingTimeMs int64 `json:"maxQueueingTimeMs"`
// BurstCount is the silent count
// BurstCount only takes effect when ControlBehavior is Reject and MetricType is QPS
BurstCount int64 `json:"burstCount"`
// DurationInSec is the time interval in statistic
// DurationInSec only takes effect when MetricType is QPS
DurationInSec int64 `json:"durationInSec"`
// ParamsMaxCapacity is the max capacity of cache statistic
ParamsMaxCapacity int64 `json:"paramsMaxCapacity"`
// SpecificItems indicates the special threshold for specific value
SpecificItems map[interface{}]int64 `json:"specificItems"`
}
func (r *Rule) String() string {
b, err := json.Marshal(r)
if err != nil {
// Return the fallback string
return fmt.Sprintf("{Id:%s, Resource:%s, MetricType:%+v, ControlBehavior:%+v, ParamIndex:%d, ParamKey:%s, Threshold:%d, MaxQueueingTimeMs:%d, BurstCount:%d, DurationInSec:%d, ParamsMaxCapacity:%d, SpecificItems:%+v}",
r.ID, r.Resource, r.MetricType, r.ControlBehavior, r.ParamIndex, r.ParamKey, r.Threshold, r.MaxQueueingTimeMs, r.BurstCount, r.DurationInSec, r.ParamsMaxCapacity, r.SpecificItems)
}
return string(b)
}
func (r *Rule) ResourceName() string {
return r.Resource
}
// IsStatReusable checks whether current rule is "statistically" equal to the given rule.
func (r *Rule) IsStatReusable(newRule *Rule) bool {
return r.Resource == newRule.Resource && r.ControlBehavior == newRule.ControlBehavior && r.ParamsMaxCapacity == newRule.ParamsMaxCapacity && r.DurationInSec == newRule.DurationInSec && r.MetricType == newRule.MetricType
}
// Equals checks whether current rule is consistent with the given rule.
func (r *Rule) Equals(newRule *Rule) bool {
baseCheck := r.Resource == newRule.Resource && r.MetricType == newRule.MetricType && r.ControlBehavior == newRule.ControlBehavior && r.ParamsMaxCapacity == newRule.ParamsMaxCapacity && r.ParamIndex == newRule.ParamIndex && r.ParamKey == newRule.ParamKey && r.Threshold == newRule.Threshold && r.DurationInSec == newRule.DurationInSec && reflect.DeepEqual(r.SpecificItems, newRule.SpecificItems)
if !baseCheck {
return false
}
if r.ControlBehavior == Reject {
return r.BurstCount == newRule.BurstCount
} else if r.ControlBehavior == Throttling {
return r.MaxQueueingTimeMs == newRule.MaxQueueingTimeMs
} else {
return false
}
}