mirror of
https://github.com/go-kratos/kratos.git
synced 2025-02-03 13:11:42 +02:00
Merge pull request #211 from kevwan/master
avoid data race while using Rand in sre_breaker.go
This commit is contained in:
commit
a65edf16ac
@ -3,6 +3,7 @@ package breaker
|
|||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -14,12 +15,14 @@ import (
|
|||||||
// sreBreaker is a sre CircuitBreaker pattern.
|
// sreBreaker is a sre CircuitBreaker pattern.
|
||||||
type sreBreaker struct {
|
type sreBreaker struct {
|
||||||
stat metric.RollingCounter
|
stat metric.RollingCounter
|
||||||
|
r *rand.Rand
|
||||||
|
// rand.New(...) returns a non thread safe object
|
||||||
|
randLock sync.Mutex
|
||||||
|
|
||||||
k float64
|
k float64
|
||||||
request int64
|
request int64
|
||||||
|
|
||||||
state int32
|
state int32
|
||||||
r *rand.Rand
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSRE(c *Config) Breaker {
|
func newSRE(c *Config) Breaker {
|
||||||
@ -69,15 +72,15 @@ func (b *sreBreaker) Allow() error {
|
|||||||
atomic.CompareAndSwapInt32(&b.state, StateClosed, StateOpen)
|
atomic.CompareAndSwapInt32(&b.state, StateClosed, StateOpen)
|
||||||
}
|
}
|
||||||
dr := math.Max(0, (float64(total)-k)/float64(total+1))
|
dr := math.Max(0, (float64(total)-k)/float64(total+1))
|
||||||
rr := b.r.Float64()
|
drop := b.trueOnProba(dr)
|
||||||
if log.V(5) {
|
if log.V(5) {
|
||||||
log.Info("breaker: drop ratio: %f, real rand: %f, drop: %v", dr, rr, dr > rr)
|
log.Info("breaker: drop ratio: %f, drop: %t", dr, drop)
|
||||||
}
|
|
||||||
if dr <= rr {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
if drop {
|
||||||
return ecode.ServiceUnavailable
|
return ecode.ServiceUnavailable
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (b *sreBreaker) MarkSuccess() {
|
func (b *sreBreaker) MarkSuccess() {
|
||||||
b.stat.Add(1)
|
b.stat.Add(1)
|
||||||
@ -88,3 +91,10 @@ func (b *sreBreaker) MarkFailed() {
|
|||||||
// drop ratio higher.
|
// drop ratio higher.
|
||||||
b.stat.Add(0)
|
b.stat.Add(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *sreBreaker) trueOnProba(proba float64) (truth bool) {
|
||||||
|
b.randLock.Lock()
|
||||||
|
truth = b.r.Float64() < proba
|
||||||
|
b.randLock.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -147,6 +147,22 @@ func TestSRESummary(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTrueOnProba(t *testing.T) {
|
||||||
|
const proba = math.Pi / 10
|
||||||
|
const total = 100000
|
||||||
|
const epsilon = 0.05
|
||||||
|
var count int
|
||||||
|
b := getSREBreaker()
|
||||||
|
for i := 0; i < total; i++ {
|
||||||
|
if b.trueOnProba(proba) {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ratio := float64(count) / float64(total)
|
||||||
|
assert.InEpsilon(t, proba, ratio, epsilon)
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkSreBreakerAllow(b *testing.B) {
|
func BenchmarkSreBreakerAllow(b *testing.B) {
|
||||||
breaker := getSRE()
|
breaker := getSRE()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user