refactor(objectnode): update ratelimit v1 lib

Signed-off-by: tangdeyi <tangdeyi@oppo.com>
This commit is contained in:
tangdeyi 2023-09-18 11:21:40 +08:00 committed by tangdeyi
parent edac86af7a
commit 15703d2c09
9 changed files with 35 additions and 120 deletions

1
go.mod
View File

@ -44,6 +44,7 @@ require (
golang.org/x/sync v0.1.0
golang.org/x/sys v0.7.0
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11
gopkg.in/bsm/ratelimit.v1 v1.0.0-20170922094635-f56db5e73a5e
gopkg.in/go-playground/validator.v9 v9.31.0
gopkg.in/natefinch/lumberjack.v2 v2.0.0
gopkg.in/yaml.v2 v2.4.0

2
go.sum
View File

@ -926,6 +926,8 @@ google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/AlecAivazis/survey.v1 v1.8.5/go.mod h1:iBNOmqKz/NUbZx3bA+4hAGLRC7fSK7tgtVDT4tB22XA=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/bsm/ratelimit.v1 v1.0.0-20170922094635-f56db5e73a5e h1:7iCTd7kl1AsKU3dJk/Y/z4WSVRe9OXA7A0tk0CBEfMA=
gopkg.in/bsm/ratelimit.v1 v1.0.0-20170922094635-f56db5e73a5e/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -194,11 +194,16 @@ func (r *UserRateMgr) QPSLimitAllowed(uid string) (bool, time.Duration) {
defaultQPSLimit := r.UserLimitConf.QPSQuota[proto.DefaultUid]
usrQPSLimit := r.UserLimitConf.QPSQuota[uid]
qpsQuota := getUserLimitQuota(defaultQPSLimit, usrQPSLimit)
if qpsQuota == 0 {
qps, err := safeConvertUint64ToInt(qpsQuota)
if err != nil {
log.LogWarnf("QPSLimitAllowed: safeConvertUint64ToInt err[%v]", err)
return true, 0
}
if qps == 0 {
return true, 0
}
log.LogDebugf("QPSLimit: defaultQPSLimit[%d] usrQPSLimit[%d] uid[%s]", defaultQPSLimit, usrQPSLimit, uid)
qpsLimit := r.QPSLimit.Acquire(uid, qpsQuota)
qpsLimit := r.QPSLimit.Acquire(uid, qps)
return !qpsLimit.Limit(), 0
}

View File

@ -26,7 +26,7 @@ type rateLimitWrapper struct {
refCount int
}
func newRateLimitWrapper(rate uint64) *rateLimitWrapper {
func newRateLimitWrapper(rate int) *rateLimitWrapper {
return &rateLimitWrapper{
r: ratelimit.New(10*rate, 10*time.Second),
refCount: 0,
@ -42,7 +42,7 @@ func NewKeyRateLimit() *KeyRateLimit {
return &KeyRateLimit{current: make(map[string]*rateLimitWrapper)}
}
func (k *KeyRateLimit) Acquire(key string, rate uint64) *ratelimit.RateLimiter {
func (k *KeyRateLimit) Acquire(key string, rate int) *ratelimit.RateLimiter {
k.mutex.Lock()
limit, ok := k.current[key]

3
vendor/gopkg.in/bsm/ratelimit.v1/Makefile generated vendored Executable file → Normal file
View File

@ -11,3 +11,6 @@ testrace: testdeps
@go test ./... -race
testall: test testrace
bench:
@go test ./... -run=NONE -bench=.

4
vendor/gopkg.in/bsm/ratelimit.v1/README.md generated vendored Executable file → Normal file
View File

@ -1,4 +1,4 @@
# RateLimit [![Build Status](https://travis-ci.org/bsm/ratelimit.png?branch=master)](https://travis-ci.org/bsm/ratelimit)
# RateLimit [![Build Status](https://travis-ci.org/bsm/ratelimit.png?branch=master)](https://travis-ci.org/bsm/ratelimit) [![Documentation](https://godoc.org/github.com/bsm/ratelimit?status.svg)](http://godoc.org/github.com/bsm/ratelimit)
Simple, thread-safe Go rate-limiter.
Inspired by Antti Huima's algorithm on http://stackoverflow.com/a/668327
@ -9,7 +9,7 @@ Inspired by Antti Huima's algorithm on http://stackoverflow.com/a/668327
package main
import (
"github.com/bsm/redeo"
"gopkg.in/bsm/ratelimit.v1"
"log"
)

23
vendor/gopkg.in/bsm/ratelimit.v1/ratelimit.go generated vendored Executable file → Normal file
View File

@ -23,13 +23,13 @@ import (
"time"
)
// RateLimit instances are thread-safe.
// RateLimiter instances are thread-safe.
type RateLimiter struct {
rate, allowance, max, unit, lastCheck uint64
}
// New creates a new rate limiter instance
func New(rate uint64, per time.Duration) *RateLimiter {
func New(rate int, per time.Duration) *RateLimiter {
nano := uint64(per)
if nano < 1 {
nano = uint64(time.Second)
@ -48,6 +48,12 @@ func New(rate uint64, per time.Duration) *RateLimiter {
}
}
// UpdateRate allows to update the allowed rate
func (rl *RateLimiter) UpdateRate(rate int) {
atomic.StoreUint64(&rl.rate, uint64(rate))
atomic.StoreUint64(&rl.max, uint64(rate)*rl.unit)
}
// Limit returns true if rate was exceeded
func (rl *RateLimiter) Limit() bool {
// Calculate the number of ns that have passed since our last call
@ -55,12 +61,13 @@ func (rl *RateLimiter) Limit() bool {
passed := now - atomic.SwapUint64(&rl.lastCheck, now)
// Add them to our allowance
current := atomic.AddUint64(&rl.allowance, passed*rl.rate)
rate := atomic.LoadUint64(&rl.rate)
current := atomic.AddUint64(&rl.allowance, passed*rate)
// Ensure our allowance is not over maximum
if current > rl.max {
atomic.AddUint64(&rl.allowance, rl.max-current)
current = rl.max
if max := atomic.LoadUint64(&rl.max); current > max {
atomic.AddUint64(&rl.allowance, max-current)
current = max
}
// If our allowance is less than one unit, rate-limit!
@ -78,8 +85,8 @@ func (rl *RateLimiter) Undo() {
current := atomic.AddUint64(&rl.allowance, rl.unit)
// Ensure our allowance is not over maximum
if current > rl.max {
atomic.AddUint64(&rl.allowance, rl.max-current)
if max := atomic.LoadUint64(&rl.max); current > max {
atomic.AddUint64(&rl.allowance, max-current)
}
}

View File

@ -1,106 +0,0 @@
package ratelimit
import (
"sync"
"testing"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("RateLimiter", func() {
It("should accurately rate-limit at small rates", func() {
var count int
rl := New(10, time.Minute)
for !rl.Limit() {
count++
}
Expect(count).To(Equal(10))
})
It("should accurately rate-limit at large rates", func() {
var count int
rl := New(100000, time.Hour)
for !rl.Limit() {
count++
}
Expect(count).To(BeNumerically("~", 100000, 10))
})
It("should accurately rate-limit at large intervals", func() {
var count int
rl := New(100, 360*24*time.Hour)
for !rl.Limit() {
count++
}
Expect(count).To(Equal(100))
})
It("should correctly increase allowance", func() {
n := 25
rl := New(n, 50*time.Millisecond)
for i := 0; i < n; i++ {
Expect(rl.Limit()).To(BeFalse(), "on cycle %d", i)
}
Expect(rl.Limit()).To(BeTrue())
Eventually(rl.Limit, "60ms", "10ms").Should(BeFalse())
})
It("should correctly spread allowance", func() {
var count int
rl := New(5, 10*time.Millisecond)
start := time.Now()
for time.Now().Sub(start) < 100*time.Millisecond {
if !rl.Limit() {
count++
}
}
Expect(count).To(BeNumerically("~", 54, 1))
})
It("should undo", func() {
rl := New(5, time.Minute)
Expect(rl.Limit()).To(BeFalse())
Expect(rl.Limit()).To(BeFalse())
Expect(rl.Limit()).To(BeFalse())
Expect(rl.Limit()).To(BeFalse())
Expect(rl.Limit()).To(BeFalse())
Expect(rl.Limit()).To(BeTrue())
rl.Undo()
Expect(rl.Limit()).To(BeFalse())
Expect(rl.Limit()).To(BeTrue())
})
It("should be thread-safe", func() {
c := 100
n := 100
wg := sync.WaitGroup{}
rl := New(c*n, time.Hour)
for i := 0; i < c; i++ {
wg.Add(1)
go func(thread int) {
defer GinkgoRecover()
defer wg.Done()
for j := 0; j < n; j++ {
Expect(rl.Limit()).To(BeFalse(), "thread %d, cycle %d", thread, j)
}
}(i)
}
wg.Wait()
Expect(rl.Limit()).To(BeTrue())
})
})
// --------------------------------------------------------------------
func TestGinkgoSuite(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "github.com/bsm/ratelimit")
}

3
vendor/modules.txt vendored
View File

@ -509,6 +509,9 @@ google.golang.org/protobuf/types/descriptorpb
google.golang.org/protobuf/types/known/anypb
google.golang.org/protobuf/types/known/durationpb
google.golang.org/protobuf/types/known/timestamppb
# gopkg.in/bsm/ratelimit.v1 v1.0.0-20170922094635-f56db5e73a5e
## explicit
gopkg.in/bsm/ratelimit.v1
# gopkg.in/go-playground/assert.v1 v1.2.1
## explicit
# gopkg.in/go-playground/validator.v9 v9.31.0