core/system/slot.go (94 lines of code) (raw):

// 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 system import ( "github.com/alibaba/sentinel-golang/core/base" "github.com/alibaba/sentinel-golang/core/stat" "github.com/alibaba/sentinel-golang/core/system_metric" ) const ( RuleCheckSlotOrder = 1000 ) var ( DefaultAdaptiveSlot = &AdaptiveSlot{} ) type AdaptiveSlot struct { } func (s *AdaptiveSlot) Order() uint32 { return RuleCheckSlotOrder } func (s *AdaptiveSlot) Check(ctx *base.EntryContext) *base.TokenResult { if ctx == nil || ctx.Resource == nil || ctx.Resource.FlowType() != base.Inbound { return nil } rules := getRules() result := ctx.RuleCheckResult for _, rule := range rules { passed, msg, snapshotValue := s.doCheckRule(rule) if passed { continue } if result == nil { result = base.NewTokenResultBlockedWithCause(base.BlockTypeSystemFlow, msg, rule, snapshotValue) } else { result.ResetToBlockedWithCause(base.BlockTypeSystemFlow, msg, rule, snapshotValue) } return result } return result } func (s *AdaptiveSlot) doCheckRule(rule *Rule) (bool, string, float64) { var msg string threshold := rule.TriggerCount switch rule.MetricType { case InboundQPS: qps := stat.InboundNode().GetQPS(base.MetricEventPass) res := qps < threshold if !res { msg = "system qps check blocked" } return res, msg, qps case Concurrency: n := float64(stat.InboundNode().CurrentConcurrency()) res := n < threshold if !res { msg = "system concurrency check blocked" } return res, msg, n case AvgRT: rt := stat.InboundNode().AvgRT() res := rt < threshold if !res { msg = "system avg rt check blocked" } return res, msg, rt case Load: l := system_metric.CurrentLoad() if l > threshold { if rule.Strategy != BBR || !checkBbrSimple() { msg = "system load check blocked" return false, msg, l } } return true, "", l case CpuUsage: c := system_metric.CurrentCpuUsage() if c > threshold { if rule.Strategy != BBR || !checkBbrSimple() { msg = "system cpu usage check blocked" return false, msg, c } } return true, "", c default: msg = "system undefined metric type, pass by default" return true, msg, 0.0 } } func checkBbrSimple() bool { concurrency := stat.InboundNode().CurrentConcurrency() minRt := stat.InboundNode().MinRT() maxComplete := stat.InboundNode().GetMaxAvg(base.MetricEventComplete) if concurrency > 1 && float64(concurrency) > maxComplete*minRt/1000.0 { return false } return true }