github.com/songzhibin97/gkit@v1.2.13/overload/bbr/bbr_test.go (about)

     1  package bbr
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math/rand"
     7  	"sync"
     8  	"sync/atomic"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/songzhibin97/gkit/internal/stat"
    13  	"github.com/songzhibin97/gkit/options"
    14  	"github.com/songzhibin97/gkit/overload"
    15  	"github.com/stretchr/testify/assert"
    16  )
    17  
    18  func confForTest() []options.Option {
    19  	return []options.Option{SetWindow(time.Second), SetWinBucket(10), SetCPUThreshold(800)}
    20  }
    21  
    22  func warmup(bbr *BBR, count int) {
    23  	for i := 0; i < count; i++ {
    24  		done, err := bbr.Allow(context.TODO())
    25  		time.Sleep(time.Millisecond * 1)
    26  		if err == nil {
    27  			done(overload.DoneInfo{Op: overload.Success})
    28  		}
    29  	}
    30  }
    31  
    32  func forceAllow(bbr *BBR) {
    33  	inflight := bbr.inFlight
    34  	bbr.inFlight = bbr.maxPASS() - 1
    35  	done, err := bbr.Allow(context.TODO())
    36  	if err == nil {
    37  		done(overload.DoneInfo{Op: overload.Success})
    38  	}
    39  	bbr.inFlight = inflight
    40  }
    41  
    42  func TestBBR(t *testing.T) {
    43  	limiter := newLimiter(SetWindow(time.Second*5), SetWinBucket(50), SetCPUThreshold(100))
    44  	var wg sync.WaitGroup
    45  	var drop int64
    46  	for i := 0; i < 100; i++ {
    47  		wg.Add(1)
    48  		go func() {
    49  			defer wg.Done()
    50  			for i := 0; i < 300; i++ {
    51  				f, err := limiter.Allow(context.TODO())
    52  				if err != nil {
    53  					atomic.AddInt64(&drop, 1)
    54  				} else {
    55  					count := rand.Intn(100)
    56  					time.Sleep(time.Millisecond * time.Duration(count))
    57  					f(overload.DoneInfo{Op: overload.Success})
    58  				}
    59  			}
    60  		}()
    61  	}
    62  	wg.Wait()
    63  	fmt.Println("drop: ", drop)
    64  }
    65  
    66  func TestBBRMaxPass(t *testing.T) {
    67  	bucketDuration := time.Millisecond * 100
    68  	bbr := newLimiter(confForTest()...).(*BBR)
    69  	for i := 1; i <= 10; i++ {
    70  		bbr.passStat.Add(int64(i * 100))
    71  		time.Sleep(bucketDuration)
    72  	}
    73  	assert.Equal(t, int64(1000), bbr.maxPASS())
    74  
    75  	// default max pass is equal to 1.
    76  	bbr = newLimiter(confForTest()...).(*BBR)
    77  	assert.Equal(t, int64(1), bbr.maxPASS())
    78  }
    79  
    80  func TestBBRMinRt(t *testing.T) {
    81  	bucketDuration := time.Millisecond * 100
    82  	bbr := newLimiter(confForTest()...).(*BBR)
    83  	rtStat := stat.NewRollingCounter(10, bucketDuration)
    84  	for i := 0; i < 10; i++ {
    85  		for j := i*10 + 1; j <= i*10+10; j++ {
    86  			rtStat.Add(int64(j))
    87  		}
    88  		if i != 9 {
    89  			time.Sleep(bucketDuration)
    90  		}
    91  	}
    92  	bbr.rtStat = rtStat
    93  	assert.Equal(t, int64(6), bbr.minRT())
    94  
    95  	// default max min rt is equal to maxFloat64.
    96  	bucketDuration = time.Millisecond * 100
    97  	bbr = newLimiter(confForTest()...).(*BBR)
    98  	bbr.rtStat = stat.NewRollingCounter(10, bucketDuration)
    99  	assert.Equal(t, int64(1), bbr.minRT())
   100  }
   101  
   102  func TestBBRMaxQps(t *testing.T) {
   103  	bbr := newLimiter(confForTest()...).(*BBR)
   104  	bucketDuration := time.Millisecond * 100
   105  	passStat := stat.NewRollingCounter(10, bucketDuration)
   106  	rtStat := stat.NewRollingCounter(10, bucketDuration)
   107  	for i := 0; i < 10; i++ {
   108  		passStat.Add(int64((i + 2) * 100))
   109  		for j := i*10 + 1; j <= i*10+10; j++ {
   110  			rtStat.Add(int64(j))
   111  		}
   112  		if i != 9 {
   113  			time.Sleep(bucketDuration)
   114  		}
   115  	}
   116  	bbr.passStat = passStat
   117  	bbr.rtStat = rtStat
   118  	assert.Equal(t, int64(60), bbr.maxFlight())
   119  }
   120  
   121  func TestBBRShouldDrop(t *testing.T) {
   122  	var cpu int64
   123  	bbr := newLimiter(confForTest()...).(*BBR)
   124  	bbr.cpu = func() int64 {
   125  		return cpu
   126  	}
   127  	bucketDuration := time.Millisecond * 100
   128  	passStat := stat.NewRollingCounter(10, bucketDuration)
   129  	rtStat := stat.NewRollingCounter(10, bucketDuration)
   130  	for i := 0; i < 10; i++ {
   131  		passStat.Add(int64((i + 1) * 100))
   132  		for j := i*10 + 1; j <= i*10+10; j++ {
   133  			rtStat.Add(int64(j))
   134  		}
   135  		if i != 9 {
   136  			time.Sleep(bucketDuration)
   137  		}
   138  	}
   139  	bbr.passStat = passStat
   140  	bbr.rtStat = rtStat
   141  	// cpu >=  800, inflight < maxQps
   142  	cpu = 800
   143  	bbr.inFlight = 50
   144  	assert.Equal(t, false, bbr.shouldDrop())
   145  
   146  	// cpu >=  800, inflight > maxQps
   147  	cpu = 800
   148  	bbr.inFlight = 80
   149  	assert.Equal(t, true, bbr.shouldDrop())
   150  
   151  	// cpu < 800, inflight > maxQps, cold duration
   152  	cpu = 700
   153  	bbr.inFlight = 80
   154  	assert.Equal(t, true, bbr.shouldDrop())
   155  
   156  	// cpu < 800, inflight > maxQps
   157  	time.Sleep(2 * time.Second)
   158  	cpu = 700
   159  	bbr.inFlight = 80
   160  	assert.Equal(t, false, bbr.shouldDrop())
   161  }
   162  
   163  func TestGroup(t *testing.T) {
   164  	group := NewGroup(SetWindow(time.Second*5), SetWinBucket(50), SetCPUThreshold(100))
   165  	t.Run("get", func(t *testing.T) {
   166  		limiter := group.Get("test")
   167  		assert.NotNil(t, limiter)
   168  	})
   169  }
   170  
   171  func BenchmarkBBRAllowUnderLowLoad(b *testing.B) {
   172  	bbr := newLimiter(confForTest()...).(*BBR)
   173  	bbr.cpu = func() int64 {
   174  		return 500
   175  	}
   176  	b.ResetTimer()
   177  	for i := 0; i <= b.N; i++ {
   178  		done, err := bbr.Allow(context.TODO())
   179  		if err == nil {
   180  			done(overload.DoneInfo{Op: overload.Success})
   181  		}
   182  	}
   183  }
   184  
   185  func BenchmarkBBRAllowUnderHighLoad(b *testing.B) {
   186  	bbr := newLimiter(confForTest()...).(*BBR)
   187  	bbr.cpu = func() int64 {
   188  		return 900
   189  	}
   190  	bbr.inFlight = 1
   191  	b.ResetTimer()
   192  	for i := 0; i <= b.N; i++ {
   193  		if i%10000 == 0 {
   194  			maxFlight := bbr.maxFlight()
   195  			if maxFlight != 0 {
   196  				bbr.inFlight = rand.Int63n(bbr.maxFlight() * 2)
   197  			}
   198  		}
   199  		done, err := bbr.Allow(context.TODO())
   200  		if err == nil {
   201  			done(overload.DoneInfo{Op: overload.Success})
   202  		}
   203  	}
   204  }
   205  
   206  func BenchmarkBBRShouldDropUnderLowLoad(b *testing.B) {
   207  	bbr := newLimiter(confForTest()...).(*BBR)
   208  	bbr.cpu = func() int64 {
   209  		return 500
   210  	}
   211  	warmup(bbr, 10000)
   212  	b.ResetTimer()
   213  	for i := 0; i <= b.N; i++ {
   214  		bbr.shouldDrop()
   215  	}
   216  }
   217  
   218  func BenchmarkBBRShouldDropUnderHighLoad(b *testing.B) {
   219  	bbr := newLimiter(confForTest()...).(*BBR)
   220  	bbr.cpu = func() int64 {
   221  		return 900
   222  	}
   223  	warmup(bbr, 10000)
   224  	bbr.inFlight = 1000
   225  	b.ResetTimer()
   226  	for i := 0; i <= b.N; i++ {
   227  		bbr.shouldDrop()
   228  		if i%10000 == 0 {
   229  			forceAllow(bbr)
   230  		}
   231  	}
   232  }
   233  
   234  func BenchmarkBBRShouldDropUnderUnstableLoad(b *testing.B) {
   235  	bbr := newLimiter(confForTest()...).(*BBR)
   236  	bbr.cpu = func() int64 {
   237  		return 500
   238  	}
   239  	warmup(bbr, 10000)
   240  	bbr.prevDrop.Store(time.Since(initTime))
   241  	bbr.inFlight = 1000
   242  	b.ResetTimer()
   243  	for i := 0; i <= b.N; i++ {
   244  		bbr.shouldDrop()
   245  		if i%100000 == 0 {
   246  			forceAllow(bbr)
   247  		}
   248  	}
   249  }