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 }