|
|
|
@ -3,6 +3,7 @@ package breaker |
|
|
|
|
import ( |
|
|
|
|
"math" |
|
|
|
|
"math/rand" |
|
|
|
|
"sync" |
|
|
|
|
"sync/atomic" |
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
@ -11,6 +12,12 @@ import ( |
|
|
|
|
"github.com/bilibili/kratos/pkg/stat/metric" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
// rand.New(...) returns a non thread safe object
|
|
|
|
|
random = rand.New(rand.NewSource(time.Now().UnixNano())) |
|
|
|
|
lock sync.Mutex |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
// sreBreaker is a sre CircuitBreaker pattern.
|
|
|
|
|
type sreBreaker struct { |
|
|
|
|
stat metric.RollingCounter |
|
|
|
@ -19,7 +26,6 @@ type sreBreaker struct { |
|
|
|
|
request int64 |
|
|
|
|
|
|
|
|
|
state int32 |
|
|
|
|
r *rand.Rand |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func newSRE(c *Config) Breaker { |
|
|
|
@ -30,7 +36,6 @@ func newSRE(c *Config) Breaker { |
|
|
|
|
stat := metric.NewRollingCounter(counterOpts) |
|
|
|
|
return &sreBreaker{ |
|
|
|
|
stat: stat, |
|
|
|
|
r: rand.New(rand.NewSource(time.Now().UnixNano())), |
|
|
|
|
|
|
|
|
|
request: c.Request, |
|
|
|
|
k: c.K, |
|
|
|
@ -69,15 +74,15 @@ func (b *sreBreaker) Allow() error { |
|
|
|
|
atomic.CompareAndSwapInt32(&b.state, StateClosed, StateOpen) |
|
|
|
|
} |
|
|
|
|
dr := math.Max(0, (float64(total)-k)/float64(total+1)) |
|
|
|
|
rr := b.r.Float64() |
|
|
|
|
drop := trueOnProba(dr) |
|
|
|
|
if log.V(5) { |
|
|
|
|
log.Info("breaker: drop ratio: %f, real rand: %f, drop: %v", dr, rr, dr > rr) |
|
|
|
|
} |
|
|
|
|
if dr <= rr { |
|
|
|
|
return nil |
|
|
|
|
log.Info("breaker: drop ratio: %f, drop: %t", dr, drop) |
|
|
|
|
} |
|
|
|
|
if drop { |
|
|
|
|
return ecode.ServiceUnavailable |
|
|
|
|
} |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (b *sreBreaker) MarkSuccess() { |
|
|
|
|
b.stat.Add(1) |
|
|
|
@ -88,3 +93,10 @@ func (b *sreBreaker) MarkFailed() { |
|
|
|
|
// drop ratio higher.
|
|
|
|
|
b.stat.Add(0) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func trueOnProba(proba float64) (truth bool) { |
|
|
|
|
lock.Lock() |
|
|
|
|
truth = random.Float64() < proba |
|
|
|
|
lock.Unlock() |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|