正确使用Go的rate limiter

经手的一部分项目使用了rate.Limiter作为限流器, 但是使用了atomic.Value包裹. 猜测本意可能是为了多协程安全, 但实际上rate.Limiter本身就支持多协程访问. 最终导致了线上限流器行为与预期不符(大约超过限流2倍左右). 在更新限流器限流的时候, 应该使用 SetLimitSetLimitAt 来更新限流配置.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
func main() {
limiter := rate.NewLimiter(rate.Limit(50000), 10)
limiterStore.Store(limiter)
ctx := context.Background()

go func() {
for {
time.Sleep(time.Second * 1)
fmt.Printf("count: %v\n", count)
}
}()

go func() {
for {
time.Sleep(time.Second * 20)
newLimiter := rate.NewLimiter(rate.Limit(50000), 10)
limiterStore.Store(newLimiter)
}
}()

for i := 0; i < 1; i++ {
go func() {
for {
beginTs := time.Now()
for j := 0; j < 10000; j++ {
_ = limiterStore.Load().(*rate.Limiter).Wait(ctx)
}
duration := time.Since(beginTs)
fmt.Printf("dur: %v\n", duration.Nanoseconds())

count++
}
}()
}

time.Sleep(time.Hour * 24)
}