Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve pooling and time retrieval mechanism to optimize performance #155

Merged
merged 3 commits into from
Jun 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 46 additions & 18 deletions api/api.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
package api

import (
"sync"

"github.com/alibaba/sentinel-golang/core/base"
)

var entryOptsPool = sync.Pool{
New: func() interface{} {
return &EntryOptions{
resourceType: base.ResTypeCommon,
entryType: base.Outbound,
acquireCount: 1,
flag: 0,
slotChain: nil,
args: nil,
attachments: nil,
}
},
}

// EntryOptions represents the options of a Sentinel resource entry.
type EntryOptions struct {
resourceType base.ResourceType
Expand All @@ -15,6 +31,16 @@ type EntryOptions struct {
attachments map[interface{}]interface{}
}

func (o *EntryOptions) Reset() {
o.resourceType = base.ResTypeCommon
o.entryType = base.Outbound
o.acquireCount = 1
o.flag = 0
o.slotChain = nil
o.args = nil
o.attachments = nil
}

type EntryOption func(*EntryOptions)

// WithResourceType sets the resource entry with the given resource type.
Expand Down Expand Up @@ -55,13 +81,19 @@ func WithArgs(args ...interface{}) EntryOption {
// WithAttachment set the resource entry with the given k-v pair
func WithAttachment(key interface{}, value interface{}) EntryOption {
return func(opts *EntryOptions) {
if opts.attachments == nil {
opts.attachments = make(map[interface{}]interface{})
}
opts.attachments[key] = value
}
}

// WithAttachment set the resource entry with the given k-v pairs
func WithAttachments(data map[interface{}]interface{}) EntryOption {
return func(opts *EntryOptions) {
if opts.attachments == nil {
opts.attachments = make(map[interface{}]interface{})
}
for key, value := range data {
opts.attachments[key] = value
}
Expand All @@ -70,20 +102,14 @@ func WithAttachments(data map[interface{}]interface{}) EntryOption {

// Entry is the basic API of Sentinel.
func Entry(resource string, opts ...EntryOption) (*base.SentinelEntry, *base.BlockError) {
var options = EntryOptions{
resourceType: base.ResTypeCommon,
entryType: base.Outbound,
acquireCount: 1,
flag: 0,
slotChain: globalSlotChain,
args: []interface{}{},
attachments: make(map[interface{}]interface{}),
}
options := entryOptsPool.Get().(*EntryOptions)
options.slotChain = globalSlotChain

for _, opt := range opts {
opt(&options)
opt(options)
}

return entry(resource, &options)
return entry(resource, options)
}

func entry(resource string, options *EntryOptions) (*base.SentinelEntry, *base.BlockError) {
Expand All @@ -96,14 +122,16 @@ func entry(resource string, options *EntryOptions) (*base.SentinelEntry, *base.B
// Get context from pool.
ctx := sc.GetPooledContext()
ctx.Resource = rw
ctx.Input = &base.SentinelInput{
AcquireCount: options.acquireCount,
Flag: options.flag,
Args: options.args,
Attachments: options.attachments,
ctx.Input.AcquireCount = options.acquireCount
ctx.Input.Flag = options.flag
if len(options.args) != 0 {
ctx.Input.Args = options.args
}
ctx.Data = make(map[interface{}]interface{})

if len(options.attachments) != 0 {
ctx.Input.Attachments = options.attachments
}
options.Reset()
entryOptsPool.Put(options)
e := base.NewSentinelEntry(ctx, rw, sc)
r := sc.Entry(ctx)
if r == nil {
Expand Down
4 changes: 4 additions & 0 deletions api/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/alibaba/sentinel-golang/core/config"
"github.com/alibaba/sentinel-golang/core/log/metric"
"github.com/alibaba/sentinel-golang/core/system"
"github.com/alibaba/sentinel-golang/util"
)

// InitDefault initializes Sentinel using the configuration from system
Expand Down Expand Up @@ -43,5 +44,8 @@ func initCoreComponents() (err error) {
}

system.InitCollector(config.SystemStatCollectIntervalMs())
if config.UseCacheTime() {
util.StartTimeTicker()
}
return err
}
20 changes: 12 additions & 8 deletions core/base/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,14 @@ type SentinelInput struct {
Attachments map[interface{}]interface{}
}

func newEmptyInput() *SentinelInput {
return &SentinelInput{
AcquireCount: 1,
Flag: 0,
Args: make([]interface{}, 0, 0),
Attachments: make(map[interface{}]interface{}),
func (i *SentinelInput) reset() {
i.AcquireCount = 1
i.Flag = 0
if len(i.Args) != 0 {
i.Args = make([]interface{}, 0)
}
if len(i.Attachments) != 0 {
i.Attachments = make(map[interface{}]interface{})
}
}

Expand All @@ -82,11 +84,13 @@ func (ctx *EntryContext) Reset() {
ctx.rt = 0
ctx.Resource = nil
ctx.StatNode = nil
ctx.Input = nil
ctx.Input.reset()
if ctx.RuleCheckResult == nil {
ctx.RuleCheckResult = NewTokenResultPass()
} else {
ctx.RuleCheckResult.ResetToPass()
}
ctx.Data = nil
if len(ctx.Data) != 0 {
ctx.Data = make(map[interface{}]interface{})
}
}
7 changes: 7 additions & 0 deletions core/base/slot_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ func NewSlotChain() *SlotChain {
New: func() interface{} {
ctx := NewEmptyEntryContext()
ctx.RuleCheckResult = NewTokenResultPass()
ctx.Data = make(map[interface{}]interface{})
ctx.Input = &SentinelInput{
AcquireCount: 1,
Flag: 0,
Args: make([]interface{}, 0),
Attachments: make(map[interface{}]interface{}),
}
return ctx
},
},
Expand Down
4 changes: 4 additions & 0 deletions core/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,7 @@ func MetricLogMaxFileAmount() uint32 {
func SystemStatCollectIntervalMs() uint32 {
return globalCfg.Sentinel.Stat.System.CollectIntervalMs
}

func UseCacheTime() bool {
return globalCfg.Sentinel.UseCacheTime
}
3 changes: 3 additions & 0 deletions core/config/entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ type SentinelConfig struct {
Log LogConfig
// Stat represents configuration items related to statistics.
Stat StatConfig
// UseCacheTime indicates whether to cache time(ms)
UseCacheTime bool `yaml:"useCacheTime"`
}

// LogConfig represent the configuration of logging in Sentinel.
Expand Down Expand Up @@ -79,6 +81,7 @@ func NewDefaultConfig() *Entity {
CollectIntervalMs: DefaultSystemStatCollectIntervalMs,
},
},
UseCacheTime: true,
},
}
}
Expand Down
4 changes: 4 additions & 0 deletions util/time.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ func FormatDate(tsMillis uint64) string {

// Returns the current Unix timestamp in milliseconds.
func CurrentTimeMillis() uint64 {
tickerNow := CurrentTimeMillWithTicker()
if tickerNow > uint64(0) {
return tickerNow
}
return uint64(time.Now().UnixNano()) / UnixTimeUnitOffset
}

Expand Down
16 changes: 16 additions & 0 deletions util/time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,19 @@ func TestCurrentTimeNano(t *testing.T) {
got := CurrentTimeNano()
fmt.Println(got)
}

func BenchmarkCurrentTimeInMs(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
CurrentTimeMillis()
}
}

func BenchmarkCurrentTimeInMsWithTicker(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
CurrentTimeMillWithTicker()
}
}
23 changes: 23 additions & 0 deletions util/time_ticker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package util

import (
"sync/atomic"
"time"
)

var nowInMs = uint64(0)

func StartTimeTicker() {
atomic.StoreUint64(&nowInMs, uint64(time.Now().UnixNano())/UnixTimeUnitOffset)
go func() {
for {
now := uint64(time.Now().UnixNano()) / UnixTimeUnitOffset
atomic.StoreUint64(&nowInMs, now)
time.Sleep(time.Millisecond)
}
}()
}

func CurrentTimeMillWithTicker() uint64 {
return atomic.LoadUint64(&nowInMs)
}
13 changes: 0 additions & 13 deletions util/util_test.go

This file was deleted.