From 9c174997570165438d90b2ba789ee57aebd5aef1 Mon Sep 17 00:00:00 2001 From: Kevin Wan Date: Thu, 15 Feb 2024 20:22:22 +0800 Subject: [PATCH] optimize: shedding algorithm performance (#3908) --- core/conf/readme.md | 2 +- core/load/adaptiveshedder.go | 32 +- core/load/adaptiveshedder_test.go | 36 ++- core/mathx/range.go | 34 ++ core/mathx/range_test.go | 513 ++++++++++++++++++++++++++++++ rest/config.go | 2 +- rest/handler/prometheushandler.go | 2 +- zrpc/config.go | 2 +- 8 files changed, 605 insertions(+), 18 deletions(-) create mode 100644 core/mathx/range.go create mode 100644 core/mathx/range_test.go diff --git a/core/conf/readme.md b/core/conf/readme.md index 7bd58540..c34a3b67 100644 --- a/core/conf/readme.md +++ b/core/conf/readme.md @@ -12,7 +12,7 @@ type RestfulConf struct { MaxConns int `json:",default=10000"` MaxBytes int64 `json:",default=1048576"` Timeout time.Duration `json:",default=3s"` - CpuThreshold int64 `json:",default=900,range=[0:1000]"` + CpuThreshold int64 `json:",default=900,range=[0:1000)"` } ``` diff --git a/core/load/adaptiveshedder.go b/core/load/adaptiveshedder.go index 4d1b7f1d..a7b6f49d 100644 --- a/core/load/adaptiveshedder.go +++ b/core/load/adaptiveshedder.go @@ -9,6 +9,7 @@ import ( "github.com/zeromicro/go-zero/core/collection" "github.com/zeromicro/go-zero/core/logx" + "github.com/zeromicro/go-zero/core/mathx" "github.com/zeromicro/go-zero/core/stat" "github.com/zeromicro/go-zero/core/syncx" "github.com/zeromicro/go-zero/core/timex" @@ -21,8 +22,11 @@ const ( defaultCpuThreshold = 900 defaultMinRt = float64(time.Second / time.Millisecond) // moving average hyperparameter beta for calculating requests on the fly - flyingBeta = 0.9 - coolOffDuration = time.Second + flyingBeta = 0.9 + coolOffDuration = time.Second + cpuMax = 1000 // millicpu + millisecondsPerSecond = 1000 + overloadFactorLowerBound = 0.1 ) var ( @@ -66,7 +70,7 @@ type ( adaptiveShedder struct { cpuThreshold int64 - windows int64 + windowScale float64 flying int64 avgFlying float64 avgFlyingLock syncx.SpinLock @@ -105,7 +109,7 @@ func NewAdaptiveShedder(opts ...ShedderOption) Shedder { bucketDuration := options.window / time.Duration(options.buckets) return &adaptiveShedder{ cpuThreshold: options.cpuThreshold, - windows: int64(time.Second / bucketDuration), + windowScale: float64(time.Second) / float64(bucketDuration) / millisecondsPerSecond, overloadTime: syncx.NewAtomicDuration(), droppedRecently: syncx.NewAtomicBool(), passCounter: collection.NewRollingWindow(options.buckets, bucketDuration, @@ -149,16 +153,17 @@ func (as *adaptiveShedder) highThru() bool { as.avgFlyingLock.Lock() avgFlying := as.avgFlying as.avgFlyingLock.Unlock() - maxFlight := as.maxFlight() - return int64(avgFlying) > maxFlight && atomic.LoadInt64(&as.flying) > maxFlight + maxFlight := as.maxFlight() * as.overloadFactor() + return avgFlying > maxFlight && float64(atomic.LoadInt64(&as.flying)) > maxFlight } -func (as *adaptiveShedder) maxFlight() int64 { +func (as *adaptiveShedder) maxFlight() float64 { // windows = buckets per second // maxQPS = maxPASS * windows // minRT = min average response time in milliseconds - // maxQPS * minRT / milliseconds_per_second - return int64(math.Max(1, float64(as.maxPass()*as.windows)*(as.minRt()/1e3))) + // allowedFlying = maxQPS * minRT / milliseconds_per_second + maxFlight := float64(as.maxPass()) * as.minRt() * as.windowScale + return mathx.AtLeast(maxFlight, 1) } func (as *adaptiveShedder) maxPass() int64 { @@ -174,6 +179,8 @@ func (as *adaptiveShedder) maxPass() int64 { } func (as *adaptiveShedder) minRt() float64 { + // if no requests in previous windows, return defaultMinRt, + // its a reasonable large value to avoid dropping requests. result := defaultMinRt as.rtCounter.Reduce(func(b *collection.Bucket) { @@ -190,6 +197,13 @@ func (as *adaptiveShedder) minRt() float64 { return result } +func (as *adaptiveShedder) overloadFactor() float64 { + // as.cpuThreshold must be less than cpuMax + factor := (cpuMax - float64(stat.CpuUsage())) / (cpuMax - float64(as.cpuThreshold)) + // at least accept 10% of acceptable requests even cpu is highly overloaded. + return mathx.Between(factor, overloadFactorLowerBound, 1) +} + func (as *adaptiveShedder) shouldDrop() bool { if as.systemOverloaded() || as.stillHot() { if as.highThru() { diff --git a/core/load/adaptiveshedder_test.go b/core/load/adaptiveshedder_test.go index 94789322..104be20e 100644 --- a/core/load/adaptiveshedder_test.go +++ b/core/load/adaptiveshedder_test.go @@ -19,6 +19,7 @@ import ( const ( buckets = 10 bucketDuration = time.Millisecond * 50 + windowFactor = 0.01 ) func init() { @@ -114,10 +115,10 @@ func TestAdaptiveShedderMaxFlight(t *testing.T) { shedder := &adaptiveShedder{ passCounter: passCounter, rtCounter: rtCounter, - windows: buckets, + windowScale: windowFactor, droppedRecently: syncx.NewAtomicBool(), } - assert.Equal(t, int64(54), shedder.maxFlight()) + assert.Equal(t, float64(54), shedder.maxFlight()) } func TestAdaptiveShedderShouldDrop(t *testing.T) { @@ -136,7 +137,7 @@ func TestAdaptiveShedderShouldDrop(t *testing.T) { shedder := &adaptiveShedder{ passCounter: passCounter, rtCounter: rtCounter, - windows: buckets, + windowScale: windowFactor, overloadTime: syncx.NewAtomicDuration(), droppedRecently: syncx.NewAtomicBool(), } @@ -149,7 +150,8 @@ func TestAdaptiveShedderShouldDrop(t *testing.T) { // cpu >= 800, inflight > maxPass shedder.avgFlying = 80 - shedder.flying = 50 + // because of the overloadFactor, so we need to make sure maxFlight is greater than flying + shedder.flying = int64(shedder.maxFlight()*shedder.overloadFactor()) - 5 assert.False(t, shedder.shouldDrop()) // cpu >= 800, inflight > maxPass @@ -190,7 +192,7 @@ func TestAdaptiveShedderStillHot(t *testing.T) { shedder := &adaptiveShedder{ passCounter: passCounter, rtCounter: rtCounter, - windows: buckets, + windowScale: windowFactor, overloadTime: syncx.NewAtomicDuration(), droppedRecently: syncx.ForAtomicBool(true), } @@ -239,6 +241,30 @@ func BenchmarkAdaptiveShedder_Allow(b *testing.B) { b.Run("low load", bench) } +func BenchmarkMaxFlight(b *testing.B) { + passCounter := newRollingWindow() + rtCounter := newRollingWindow() + for i := 0; i < 10; i++ { + if i > 0 { + time.Sleep(bucketDuration) + } + passCounter.Add(float64((i + 1) * 100)) + for j := i*10 + 1; j <= i*10+10; j++ { + rtCounter.Add(float64(j)) + } + } + shedder := &adaptiveShedder{ + passCounter: passCounter, + rtCounter: rtCounter, + windowScale: windowFactor, + droppedRecently: syncx.NewAtomicBool(), + } + + for i := 0; i < b.N; i++ { + _ = shedder.maxFlight() + } +} + func newRollingWindow() *collection.RollingWindow { return collection.NewRollingWindow(buckets, bucketDuration, collection.IgnoreCurrentBucket()) } diff --git a/core/mathx/range.go b/core/mathx/range.go new file mode 100644 index 00000000..d74ac4dd --- /dev/null +++ b/core/mathx/range.go @@ -0,0 +1,34 @@ +package mathx + +type numerical interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 | + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | + ~float32 | ~float64 +} + +// AtLeast returns the greater of x or lower. +func AtLeast[T numerical](x, lower T) T { + if x < lower { + return lower + } + return x +} + +// AtMost returns the smaller of x or upper. +func AtMost[T numerical](x, upper T) T { + if x > upper { + return upper + } + return x +} + +// Between returns the value of x clamped to the range [lower, upper]. +func Between[T numerical](x, lower, upper T) T { + if x < lower { + return lower + } + if x > upper { + return upper + } + return x +} diff --git a/core/mathx/range_test.go b/core/mathx/range_test.go new file mode 100644 index 00000000..bff9c2bc --- /dev/null +++ b/core/mathx/range_test.go @@ -0,0 +1,513 @@ +package mathx + +import "testing" + +func TestAtLeast(t *testing.T) { + t.Run("test int", func(t *testing.T) { + if got := AtLeast(10, 5); got != 10 { + t.Errorf("AtLeast() = %v, want 10", got) + } + if got := AtLeast(3, 5); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + if got := AtLeast(5, 5); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + }) + + t.Run("test int8", func(t *testing.T) { + if got := AtLeast(int8(10), int8(5)); got != 10 { + t.Errorf("AtLeast() = %v, want 10", got) + } + if got := AtLeast(int8(3), int8(5)); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + if got := AtLeast(int8(5), int8(5)); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + }) + + t.Run("test int16", func(t *testing.T) { + if got := AtLeast(int16(10), int16(5)); got != 10 { + t.Errorf("AtLeast() = %v, want 10", got) + } + if got := AtLeast(int16(3), int16(5)); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + if got := AtLeast(int16(5), int16(5)); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + }) + + t.Run("test int32", func(t *testing.T) { + if got := AtLeast(int32(10), int32(5)); got != 10 { + t.Errorf("AtLeast() = %v, want 10", got) + } + if got := AtLeast(int32(3), int32(5)); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + if got := AtLeast(int32(5), int32(5)); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + }) + + t.Run("test int64", func(t *testing.T) { + if got := AtLeast(int64(10), int64(5)); got != 10 { + t.Errorf("AtLeast() = %v, want 10", got) + } + if got := AtLeast(int64(3), int64(5)); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + if got := AtLeast(int64(5), int64(5)); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + }) + + t.Run("test uint", func(t *testing.T) { + if got := AtLeast(uint(10), uint(5)); got != 10 { + t.Errorf("AtLeast() = %v, want 10", got) + } + if got := AtLeast(uint(3), uint(5)); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + if got := AtLeast(uint(5), uint(5)); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + }) + + t.Run("test uint8", func(t *testing.T) { + if got := AtLeast(uint8(10), uint8(5)); got != 10 { + t.Errorf("AtLeast() = %v, want 10", got) + } + if got := AtLeast(uint8(3), uint8(5)); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + if got := AtLeast(uint8(5), uint8(5)); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + }) + + t.Run("test uint16", func(t *testing.T) { + if got := AtLeast(uint16(10), uint16(5)); got != 10 { + t.Errorf("AtLeast() = %v, want 10", got) + } + if got := AtLeast(uint16(3), uint16(5)); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + if got := AtLeast(uint16(5), uint16(5)); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + }) + + t.Run("test uint32", func(t *testing.T) { + if got := AtLeast(uint32(10), uint32(5)); got != 10 { + t.Errorf("AtLeast() = %v, want 10", got) + } + if got := AtLeast(uint32(3), uint32(5)); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + if got := AtLeast(uint32(5), uint32(5)); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + }) + + t.Run("test uint64", func(t *testing.T) { + if got := AtLeast(uint64(10), uint64(5)); got != 10 { + t.Errorf("AtLeast() = %v, want 10", got) + } + if got := AtLeast(uint64(3), uint64(5)); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + if got := AtLeast(uint64(5), uint64(5)); got != 5 { + t.Errorf("AtLeast() = %v, want 5", got) + } + }) + + t.Run("test float32", func(t *testing.T) { + if got := AtLeast(float32(10.0), float32(5.0)); got != 10.0 { + t.Errorf("AtLeast() = %v, want 10.0", got) + } + if got := AtLeast(float32(3.0), float32(5.0)); got != 5.0 { + t.Errorf("AtLeast() = %v, want 5.0", got) + } + if got := AtLeast(float32(5.0), float32(5.0)); got != 5.0 { + t.Errorf("AtLeast() = %v, want 5.0", got) + } + }) + + t.Run("test float64", func(t *testing.T) { + if got := AtLeast(10.0, 5.0); got != 10.0 { + t.Errorf("AtLeast() = %v, want 10.0", got) + } + if got := AtLeast(3.0, 5.0); got != 5.0 { + t.Errorf("AtLeast() = %v, want 5.0", got) + } + if got := AtLeast(5.0, 5.0); got != 5.0 { + t.Errorf("AtLeast() = %v, want 5.0", got) + } + }) +} + +func TestAtMost(t *testing.T) { + t.Run("test int", func(t *testing.T) { + if got := AtMost(10, 5); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + if got := AtMost(3, 5); got != 3 { + t.Errorf("AtMost() = %v, want 3", got) + } + if got := AtMost(5, 5); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + }) + + t.Run("test int8", func(t *testing.T) { + if got := AtMost(int8(10), int8(5)); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + if got := AtMost(int8(3), int8(5)); got != 3 { + t.Errorf("AtMost() = %v, want 3", got) + } + if got := AtMost(int8(5), int8(5)); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + }) + + t.Run("test int16", func(t *testing.T) { + if got := AtMost(int16(10), int16(5)); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + if got := AtMost(int16(3), int16(5)); got != 3 { + t.Errorf("AtMost() = %v, want 3", got) + } + if got := AtMost(int16(5), int16(5)); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + }) + + t.Run("test int32", func(t *testing.T) { + if got := AtMost(int32(10), int32(5)); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + if got := AtMost(int32(3), int32(5)); got != 3 { + t.Errorf("AtMost() = %v, want 3", got) + } + if got := AtMost(int32(5), int32(5)); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + }) + + t.Run("test int64", func(t *testing.T) { + if got := AtMost(int64(10), int64(5)); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + if got := AtMost(int64(3), int64(5)); got != 3 { + t.Errorf("AtMost() = %v, want 3", got) + } + if got := AtMost(int64(5), int64(5)); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + }) + + t.Run("test uint", func(t *testing.T) { + if got := AtMost(uint(10), uint(5)); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + if got := AtMost(uint(3), uint(5)); got != 3 { + t.Errorf("AtMost() = %v, want 3", got) + } + if got := AtMost(uint(5), uint(5)); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + }) + + t.Run("test uint8", func(t *testing.T) { + if got := AtMost(uint8(10), uint8(5)); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + if got := AtMost(uint8(3), uint8(5)); got != 3 { + t.Errorf("AtMost() = %v, want 3", got) + } + if got := AtMost(uint8(5), uint8(5)); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + }) + + t.Run("test uint16", func(t *testing.T) { + if got := AtMost(uint16(10), uint16(5)); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + if got := AtMost(uint16(3), uint16(5)); got != 3 { + t.Errorf("AtMost() = %v, want 3", got) + } + if got := AtMost(uint16(5), uint16(5)); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + }) + + t.Run("test uint32", func(t *testing.T) { + if got := AtMost(uint32(10), uint32(5)); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + if got := AtMost(uint32(3), uint32(5)); got != 3 { + t.Errorf("AtMost() = %v, want 3", got) + } + if got := AtMost(uint32(5), uint32(5)); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + }) + + t.Run("test uint64", func(t *testing.T) { + if got := AtMost(uint64(10), uint64(5)); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + if got := AtMost(uint64(3), uint64(5)); got != 3 { + t.Errorf("AtMost() = %v, want 3", got) + } + if got := AtMost(uint64(5), uint64(5)); got != 5 { + t.Errorf("AtMost() = %v, want 5", got) + } + }) + + t.Run("test float32", func(t *testing.T) { + if got := AtMost(float32(10.0), float32(5.0)); got != 5.0 { + t.Errorf("AtMost() = %v, want 5.0", got) + } + if got := AtMost(float32(3.0), float32(5.0)); got != 3.0 { + t.Errorf("AtMost() = %v, want 3.0", got) + } + if got := AtMost(float32(5.0), float32(5.0)); got != 5.0 { + t.Errorf("AtMost() = %v, want 5.0", got) + } + }) + + t.Run("test float64", func(t *testing.T) { + if got := AtMost(10.0, 5.0); got != 5.0 { + t.Errorf("AtMost() = %v, want 5.0", got) + } + if got := AtMost(3.0, 5.0); got != 3.0 { + t.Errorf("AtMost() = %v, want 3.0", got) + } + if got := AtMost(5.0, 5.0); got != 5.0 { + t.Errorf("AtMost() = %v, want 5.0", got) + } + }) +} + +func TestBetween(t *testing.T) { + t.Run("test int", func(t *testing.T) { + if got := Between(10, 5, 15); got != 10 { + t.Errorf("Between() = %v, want 10", got) + } + if got := Between(3, 5, 15); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(20, 5, 15); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + if got := Between(5, 5, 15); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(15, 5, 15); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + }) + + t.Run("test int8", func(t *testing.T) { + if got := Between(int8(10), int8(5), int8(15)); got != 10 { + t.Errorf("Between() = %v, want 10", got) + } + if got := Between(int8(3), int8(5), int8(15)); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(int8(20), int8(5), int8(15)); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + if got := Between(int8(5), int8(5), int8(15)); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(int8(15), int8(5), int8(15)); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + }) + + t.Run("test int16", func(t *testing.T) { + if got := Between(int16(10), int16(5), int16(15)); got != 10 { + t.Errorf("Between() = %v, want 10", got) + } + if got := Between(int16(3), int16(5), int16(15)); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(int16(20), int16(5), int16(15)); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + if got := Between(int16(5), int16(5), int16(15)); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(int16(15), int16(5), int16(15)); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + }) + + t.Run("test int32", func(t *testing.T) { + if got := Between(int32(10), int32(5), int32(15)); got != 10 { + t.Errorf("Between() = %v, want 10", got) + } + if got := Between(int32(3), int32(5), int32(15)); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(int32(20), int32(5), int32(15)); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + if got := Between(int32(5), int32(5), int32(15)); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(int32(15), int32(5), int32(15)); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + }) + + t.Run("test int64", func(t *testing.T) { + if got := Between(int64(10), int64(5), int64(15)); got != 10 { + t.Errorf("Between() = %v, want 10", got) + } + if got := Between(int64(3), int64(5), int64(15)); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(int64(20), int64(5), int64(15)); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + if got := Between(int64(5), int64(5), int64(15)); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(int64(15), int64(5), int64(15)); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + }) + + t.Run("test uint", func(t *testing.T) { + if got := Between(uint(10), uint(5), uint(15)); got != 10 { + t.Errorf("Between() = %v, want 10", got) + } + if got := Between(uint(3), uint(5), uint(15)); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(uint(20), uint(5), uint(15)); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + if got := Between(uint(5), uint(5), uint(15)); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(uint(15), uint(5), uint(15)); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + }) + + t.Run("test uint8", func(t *testing.T) { + if got := Between(uint8(10), uint8(5), uint8(15)); got != 10 { + t.Errorf("Between() = %v, want 10", got) + } + if got := Between(uint8(3), uint8(5), uint8(15)); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(uint8(20), uint8(5), uint8(15)); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + if got := Between(uint8(5), uint8(5), uint8(15)); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(uint8(15), uint8(5), uint8(15)); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + }) + + t.Run("test uint16", func(t *testing.T) { + if got := Between(uint16(10), uint16(5), uint16(15)); got != 10 { + t.Errorf("Between() = %v, want 10", got) + } + if got := Between(uint16(3), uint16(5), uint16(15)); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(uint16(20), uint16(5), uint16(15)); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + if got := Between(uint16(5), uint16(5), uint16(15)); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(uint16(15), uint16(5), uint16(15)); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + }) + + t.Run("test uint32", func(t *testing.T) { + if got := Between(uint32(10), uint32(5), uint32(15)); got != 10 { + t.Errorf("Between() = %v, want 10", got) + } + if got := Between(uint32(3), uint32(5), uint32(15)); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(uint32(20), uint32(5), uint32(15)); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + if got := Between(uint32(5), uint32(5), uint32(15)); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(uint32(15), uint32(5), uint32(15)); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + }) + + t.Run("test uint64", func(t *testing.T) { + if got := Between(uint64(10), uint64(5), uint64(15)); got != 10 { + t.Errorf("Between() = %v, want 10", got) + } + if got := Between(uint64(3), uint64(5), uint64(15)); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(uint64(20), uint64(5), uint64(15)); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + if got := Between(uint64(5), uint64(5), uint64(15)); got != 5 { + t.Errorf("Between() = %v, want 5", got) + } + if got := Between(uint64(15), uint64(5), uint64(15)); got != 15 { + t.Errorf("Between() = %v, want 15", got) + } + }) + + t.Run("test float32", func(t *testing.T) { + if got := Between(float32(10.0), float32(5.0), float32(15.0)); got != 10.0 { + t.Errorf("Between() = %v, want 10.0", got) + } + if got := Between(float32(3.0), float32(5.0), float32(15.0)); got != 5.0 { + t.Errorf("Between() = %v, want 5.0", got) + } + if got := Between(float32(20.0), float32(5.0), float32(15.0)); got != 15.0 { + t.Errorf("Between() = %v, want 15.0", got) + } + if got := Between(float32(5.0), float32(5.0), float32(15.0)); got != 5.0 { + t.Errorf("Between() = %v, want 5.0", got) + } + if got := Between(float32(15.0), float32(5.0), float32(15.0)); got != 15.0 { + t.Errorf("Between() = %v, want 15.0", got) + } + }) + + t.Run("test float64", func(t *testing.T) { + if got := Between(10.0, 5.0, 15.0); got != 10.0 { + t.Errorf("Between() = %v, want 10.0", got) + } + if got := Between(3.0, 5.0, 15.0); got != 5.0 { + t.Errorf("Between() = %v, want 5.0", got) + } + if got := Between(20.0, 5.0, 15.0); got != 15.0 { + t.Errorf("Between() = %v, want 15.0", got) + } + if got := Between(5.0, 5.0, 15.0); got != 5.0 { + t.Errorf("Between() = %v, want 5.0", got) + } + if got := Between(15.0, 5.0, 15.0); got != 15.0 { + t.Errorf("Between() = %v, want 15.0", got) + } + }) +} diff --git a/rest/config.go b/rest/config.go index ece29bfd..eb5fdb0b 100644 --- a/rest/config.go +++ b/rest/config.go @@ -53,7 +53,7 @@ type ( MaxBytes int64 `json:",default=1048576"` // milliseconds Timeout int64 `json:",default=3000"` - CpuThreshold int64 `json:",default=900,range=[0:1000]"` + CpuThreshold int64 `json:",default=900,range=[0:1000)"` Signature SignatureConf `json:",optional"` // There are default values for all the items in Middlewares. Middlewares MiddlewaresConf diff --git a/rest/handler/prometheushandler.go b/rest/handler/prometheushandler.go index 86676d4c..6abf4dee 100644 --- a/rest/handler/prometheushandler.go +++ b/rest/handler/prometheushandler.go @@ -18,7 +18,7 @@ var ( Name: "duration_ms", Help: "http server requests duration(ms).", Labels: []string{"path", "method"}, - Buckets: []float64{5, 10, 25, 50, 100, 250, 500, 1000}, + Buckets: []float64{5, 10, 25, 50, 100, 250, 500, 750, 1000}, }) metricServerReqCodeTotal = metric.NewCounterVec(&metric.CounterVecOpts{ diff --git a/zrpc/config.go b/zrpc/config.go index 84a32160..5e459a3c 100644 --- a/zrpc/config.go +++ b/zrpc/config.go @@ -43,7 +43,7 @@ type ( StrictControl bool `json:",optional"` // setting 0 means no timeout Timeout int64 `json:",default=2000"` - CpuThreshold int64 `json:",default=900,range=[0:1000]"` + CpuThreshold int64 `json:",default=900,range=[0:1000)"` // grpc health check switch Health bool `json:",default=true"` Middlewares ServerMiddlewaresConf