Repository: zeromicro/go-zero
Pull request #4151 (2024-05-14 07:21:47)

optimize: simplify breaker algorithm

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/zeromicro/go-zero/pull/4151?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=zeromicro) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 95.10%. Comparing base [(`8690859`)](https://app.codecov.io/gh/zeromicro/go-zero/commit/8690859c7d1c9461bdc422c3c65608bde30904db?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=zeromicro) to head [(`51b6665`)](https://app.codecov.io/gh/zeromicro/go-zero/pull/4151?dropdown=coverage&src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=zeromicro).
> Report is 51 commits behind head on master.

<details><summary>Additional details and impacted files</summary>



| [Files](https://app.codecov.io/gh/zeromicro/go-zero/pull/4151?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=zeromicro) | Coverage Δ | |
|---|---|---|
| [core/breaker/googlebreaker.go](https://app.codecov.io/gh/zeromicro/go-zero/pull/4151?src=pr&el=tree&filepath=core%2Fbreaker%2Fgooglebreaker.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=zeromicro#diff-Y29yZS9icmVha2VyL2dvb2dsZWJyZWFrZXIuZ28=) | `95.94% <100.00%> (-4.06%)` | :arrow_down: |

... and [254 files with indirect coverage changes](https://app.codecov.io/gh/zeromicro/go-zero/pull/4151/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=zeromicro)

</details>

Patch:
diff --git a/core/breaker/googlebreaker.go b/core/breaker/googlebreaker.go
index 11b7c456..0721663e 100644
--- a/core/breaker/googlebreaker.go
+++ b/core/breaker/googlebreaker.go
@@ -11,15 +11,12 @@ import (
 
 const (
 	// 250ms for bucket duration
-	window                    = time.Second * 10
-	buckets                   = 40
-	maxFailBucketsToDecreaseK = 30
-	minBucketsToSpeedUp       = 3
-	forcePassDuration         = time.Second
-	k                         = 1.5
-	minK                      = 1.1
-	recoveryK                 = 4 - k
-	protection                = 5
+	window            = time.Second * 10
+	buckets           = 40
+	forcePassDuration = time.Second
+	k                 = 1.5
+	minK              = 1.1
+	protection        = 5
 )
 
 // googleBreaker is a netflixBreaker pattern from google.
@@ -56,13 +53,8 @@ func newGoogleBreaker() *googleBreaker {
 func (b *googleBreaker) accept() error {
 	var w float64
 	history := b.history()
-	if history.failingBuckets >= minBucketsToSpeedUp {
-		w = b.k - float64(history.failingBuckets-1)*(b.k-minK)/maxFailBucketsToDecreaseK
-		w = mathx.AtLeast(w, minK)
-	} else {
-		w = b.k
-	}
-	weightedAccepts := w * float64(history.accepts)
+	w = b.k - (b.k-minK)*float64(history.failingBuckets)/buckets
+	weightedAccepts := mathx.AtLeast(w, minK) * float64(history.accepts)
 	// https://landing.google.com/sre/sre-book/chapters/handling-overload/#eq2101
 	// for better performance, no need to care about the negative ratio
 	dropRatio := (float64(history.total-protection) - weightedAccepts) / float64(history.total+1)
@@ -76,11 +68,7 @@ func (b *googleBreaker) accept() error {
 		return nil
 	}
 
-	// If we have more than 2 working buckets, we are in recovery mode,
-	// the latest bucket is the current one, so we ignore it.
-	if history.workingBuckets >= minBucketsToSpeedUp {
-		dropRatio /= recoveryK
-	}
+	dropRatio *= float64(buckets-history.workingBuckets) / buckets
 
 	if b.proba.TrueOnProba(dropRatio) {
 		return ErrServiceUnavailable


Test patch:
diff --git a/core/breaker/googlebreaker_test.go b/core/breaker/googlebreaker_test.go
index a7df2934..0d71b912 100644
--- a/core/breaker/googlebreaker_test.go
+++ b/core/breaker/googlebreaker_test.go
@@ -127,7 +127,7 @@ func TestGoogleBreakerMoreFallingBuckets(t *testing.T) {
 		b := getGoogleBreaker()
 
 		func() {
-			stopChan := time.After(testInterval * minBucketsToSpeedUp * 2)
+			stopChan := time.After(testInterval * 6)
 			for {
 				time.Sleep(time.Millisecond)
 				select {