Understanding Sentinel-Go: Core Concepts, Flow Control Architecture, and Implementation Details

This article provides an in‑depth analysis of Sentinel‑Go, covering its fundamental concepts such as Resource and Rule, the Entry and SlotChain mechanisms, flow‑control components like TrafficShapingController, metric storage structures including BucketWrap and LeapArray, and practical code examples illustrating the library’s internal workflow.

Alibaba Cloud Native
Alibaba Cloud Native
Alibaba Cloud Native
Understanding Sentinel-Go: Core Concepts, Flow Control Architecture, and Implementation Details

Overview

Sentinel‑Go is the Go implementation of the open‑source traffic‑control middleware Sentinel. It provides a resource‑based flow‑control mechanism built on a slot‑chain pipeline and a sliding‑window metric system.

Core Types

Resource

A resource is represented by ResourceWrapper, which stores a unique name, a ResourceType (common, web, RPC) and a TrafficType (inbound/provider or outbound/consumer).

type ResourceType int32
const (
    ResTypeCommon ResourceType = iota
    ResTypeWeb
    ResTypeRPC
)

type TrafficType int32
const (
    Inbound TrafficType = iota // provider side
    Outbound                   // consumer side
)

type ResourceWrapper struct {
    name           string
    classification ResourceType
    flowType       TrafficType
}

Rule

A Rule describes the flow‑control strategy for a resource: threshold (QPS), control behavior (reject or throttling), statistic interval and maximum queueing time.

type ControlBehavior int32
const (
    Reject ControlBehavior = iota
    Throttling
)

type Rule struct {
    Resource          string          `json:"resource"`
    ControlBehavior   ControlBehavior `json:"controlBehavior"`
    Threshold         float64         `json:"threshold"` // QPS when StatIntervalInMs = 1000
    MaxQueueingTimeMs uint32          `json:"maxQueueingTimeMs"`
    StatIntervalInMs  uint32          `json:"statIntervalInMs"`
}

Entry and Context

An Entry binds a ResourceWrapper with a SlotChain. The EntryContext holds the resource, a StatNode for metrics, input parameters and the result of rule checks.

type EntryOptions struct {
    resourceType base.ResourceType
    entryType    base.TrafficType
    acquireCount uint32
    slotChain    *base.SlotChain
}

type EntryContext struct {
    entry            *SentinelEntry
    startTime        uint64
    Resource         *ResourceWrapper
    StatNode         StatNode
    Input            *SentinelInput
    RuleCheckResult  *TokenResult
}

Flow‑Control Components

TrafficShapingController

The controller combines a TrafficShapingCalculator (calculates allowed tokens) and a TrafficShapingChecker (performs the actual check).

type TrafficShapingCalculator interface {
    CalculateAllowedTokens(acquireCount uint32, flag int32) float64
}

type DirectTrafficShapingCalculator struct {
    threshold float64
}
func (d *DirectTrafficShapingCalculator) CalculateAllowedTokens(uint32, int32) float64 {
    return d.threshold
}

type TrafficShapingChecker interface {
    DoCheck(resStat base.StatNode, acquireCount uint32, threshold float64) *base.TokenResult
}

type RejectTrafficShapingChecker struct {
    rule *Rule
}
func (d *RejectTrafficShapingChecker) DoCheck(resStat base.StatNode, acquireCount uint32, threshold float64) *base.TokenResult {
    curCount := float64(resStat.GetSum(base.MetricEventPass))
    if curCount+float64(acquireCount) > threshold {
        return base.NewTokenResultBlockedWithCause(base.BlockTypeFlow, "", d.rule, curCount)
    }
    return nil
}

The controller’s PerformChecking obtains the current metric, calculates allowed tokens and delegates to the checker.

type TrafficShapingController struct {
    flowCalculator TrafficShapingCalculator
    flowChecker    TrafficShapingChecker
    rule           *Rule
    boundStat      standaloneStatistic
}
func (t *TrafficShapingController) PerformChecking(acquireCount uint32, flag int32) *base.TokenResult {
    allowedTokens := t.flowCalculator.CalculateAllowedTokens(acquireCount, flag)
    return t.flowChecker.DoCheck(t.boundStat.readOnlyMetric, acquireCount, allowedTokens)
}

TrafficControllerMap

All controllers are stored in a map keyed by resource name.

type TrafficControllerMap map[string][]*TrafficShapingController
var tcMap = make(TrafficControllerMap)

When LoadRules() is called, a TrafficShapingController is created for each rule and registered in tcMap.

Sliding‑Window Metrics

Metrics are kept in a time‑wheel built from BucketWrap (start timestamp + atomic MetricBucket), AtomicBucketWrapArray and LeapArray. The smallest unit is a bucket; a LeapArray holds a fixed number of buckets and provides currentBucketOfTime to locate the bucket for a given timestamp.

type BucketWrap struct {
    BucketStart uint64
    Value       atomic.Value // holds *MetricBucket
}

type MetricBucket struct {
    counter [base.MetricEventTotal]int64
    minRt   int64
}

type AtomicBucketWrapArray struct {
    base   unsafe.Pointer
    length int
    data   []*BucketWrap
}

type LeapArray struct {
    bucketLengthInMs uint32
    sampleCount      uint32
    intervalInMs     uint32
    array            *AtomicBucketWrapArray
    updateLock       mutex
}
func (la *LeapArray) currentBucketOfTime(now uint64, bg BucketGenerator) (*BucketWrap, error) {
    // core loop that creates or resets buckets atomically
}

type SlidingWindowMetric struct {
    bucketLengthInMs uint32
    sampleCount      uint32
    intervalInMs     uint32
    real             *BucketLeapArray
}

Slot Chain Architecture

The processing pipeline consists of three slot categories:

StatPrepareSlot : creates or fetches the ResourceNode and stores it in the context.

RuleCheckSlot : iterates over all rules for the resource and applies the corresponding TrafficShapingController.

StatSlot : records metrics after a pass or block and updates the sliding‑window counters.

During SlotChain.Entry() the slots are executed in the order prepare → rule check → statistic. After the business logic finishes, SlotChain.exit() invokes StatSlot.OnCompleted for each slot.

func (sc *SlotChain) Entry(ctx *EntryContext) *TokenResult {
    for _, s := range sc.statPres { s.Prepare(ctx) }
    for _, s := range sc.ruleChecks {
        r := s.Check(ctx)
        if r != nil && r.IsBlocked() {
            ctx.RuleCheckResult = r
            break
        }
    }
    for _, s := range sc.stats {
        if ctx.RuleCheckResult.IsBlocked() {
            s.OnEntryBlocked(ctx, ctx.RuleCheckResult.blockErr)
        } else {
            s.OnEntryPassed(ctx)
        }
    }
    return ctx.RuleCheckResult
}
func (sc *SlotChain) exit(ctx *EntryContext) {
    if ctx.IsBlocked() { return }
    for _, s := range sc.stats { s.OnCompleted(ctx) }
}

The global variable globalSlotChain holds the default chain used by the public api.Entry() function.

func BuildDefaultSlotChain() *base.SlotChain {
    sc := base.NewSlotChain()
    sc.AddStatPrepareSlotLast(&stat.ResourceNodePrepareSlot{})
    sc.AddRuleCheckSlotLast(&flow.Slot{})
    sc.AddStatSlotLast(&flow.StandaloneStatSlot{})
    return sc
}
var globalSlotChain = BuildDefaultSlotChain()

Key Algorithms

Direct + Reject Flow

In the simplest case the controller uses DirectTrafficShapingCalculator (returns the rule threshold) and RejectTrafficShapingChecker. The check logic is:

Read the current pass count from the bound statistic.

If curCount + acquireCount > Rule.Threshold the request is blocked; otherwise it passes.

Throttling (Rate‑Limiting)

The ThrottlingChecker (not shown) splits a time window into micro‑buckets, allowing at most one request per micro‑bucket. The possible TokenResultStatus values are Pass, Wait (request is delayed) and Blocked (wait time exceeds Rule.MaxQueueingTimeMs).

Metric Collection Details

Each bucket records five event counters:

const (
    MetricEventPass MetricEvent = iota
    MetricEventBlock
    MetricEventComplete
    MetricEventError
    MetricEventRt
    MetricEventTotal
)

The MetricBucket stores these counters and the minimum response time ( minRt). Buckets are managed by AtomicBucketWrapArray, which holds a fixed‑size slice of pointers to BucketWrap. The LeapArray calculates the bucket index and start time, creates new buckets atomically, and resets stale buckets when the time advances.

Load Rules and Statistic Nodes

core/flow/rule_manager.go:LoadRules()

converts user‑defined Rule objects into TrafficShapingController instances, creates a standaloneStatistic (either reusing the resource’s default metric or allocating a dedicated one) and stores the controller in tcMap.

func generateStatFor(rule *Rule) (*standaloneStatistic, error) {
    resNode := stat.GetOrCreateResourceNode(rule.Resource, base.ResTypeCommon)
    readStat := resNode.DefaultMetric()
    retStat.reuseResourceStat = true
    retStat.readOnlyMetric = readStat
    retStat.writeOnlyMetric = nil
    return &retStat, nil
}

Entry/Exit Flow

Typical usage:

entry, blockErr := sentinel.Entry("myResource")
if blockErr != nil {
    // request is blocked
    return
}
defer entry.Exit() // triggers SlotChain.exit()
// business logic here

Community Improvements

PR 263 introduced a configurable flow‑control component selection, reducing the number of rule checks and yielding ~15 % performance gain. Further refinements are tracked in PR 264.

PR 263: https://github.com/alibaba/sentinel-golang/pull/263

PR 264: https://github.com/alibaba/sentinel-golang/pull/264

References

Sentinel‑Go repository: https://github.com/alibaba/sentinel-golang

Sentinel architecture diagram
Sentinel architecture diagram
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

GometricssentinelOpenSourceFlowControlSlidingWindowSlotChain
Alibaba Cloud Native
Written by

Alibaba Cloud Native

We publish cloud-native tech news, curate in-depth content, host regular events and live streams, and share Alibaba product and user case studies. Join us to explore and share the cloud-native insights you need.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.