1
0
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:
Terry.Mao 2019-07-22 10:40:38 +08:00 committed by GitHub
commit a65edf16ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 7 deletions

View File

@ -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
}

View File

@ -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()