mirror of
https://github.com/cubefs/cubefs.git
synced 2026-08-02 02:00:56 +00:00
refactor(objectnode): update ratelimit v1 lib
Signed-off-by: tangdeyi <tangdeyi@oppo.com>
This commit is contained in:
parent
edac86af7a
commit
15703d2c09
1
go.mod
1
go.mod
@ -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
2
go.sum
@ -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=
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
3
vendor/gopkg.in/bsm/ratelimit.v1/Makefile
generated
vendored
Executable file → Normal 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
4
vendor/gopkg.in/bsm/ratelimit.v1/README.md
generated
vendored
Executable file → Normal file
@ -1,4 +1,4 @@
|
||||
# RateLimit [](https://travis-ci.org/bsm/ratelimit)
|
||||
# RateLimit [](https://travis-ci.org/bsm/ratelimit) [](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
23
vendor/gopkg.in/bsm/ratelimit.v1/ratelimit.go
generated
vendored
Executable file → Normal 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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
106
vendor/gopkg.in/bsm/ratelimit.v1/ratelimit_test.go
generated
vendored
106
vendor/gopkg.in/bsm/ratelimit.v1/ratelimit_test.go
generated
vendored
@ -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
3
vendor/modules.txt
vendored
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user