time.Duration的理解
假设,我们指定的生成令牌的速率是每秒产生965个令牌,那么每生成一个令牌的间隔是多少呢?大约是每1.0362毫秒产生一个令牌。那么如果是在100毫秒这段时间会产生多少个令牌呢?大约103.62个令牌。
好了,既然是float64,那么在计算给定时间段内产生的tokens总数时就会有精度问题。我们来看看time/rate包中限速器的某段代码
func (limit Limit) tokensFromDuration(d time.Duration) float64 {
sec := float64(d/time.Second) * float64(limit)
nsec := float64(d%time.Second) * float64(limit)
return sec + nsec/1e9
}
//疑问,为什么要按照秒来计算,直接计算每纳秒产生多少个,然后计算过了多少纳秒不就好了?
fmt.Println((float64(3) / float64(time.Second)) * 123123) //0.000369369
time.Duration 是 int64 的别名,代表纳秒。分别求出秒的整数部分和小数部分,进行相乘后再相加,这样可以得到最精确的精度。
type Duration int64
const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minute = 60 * Second
Hour = 60 * Minute
)
start := time.Now()
fmt.Printf("t:%d\n", time.Now().Sub(start)) //这里打印出来的是纳秒
time.Sleep(1*time.Second) //sleep函数的参数值其实是int64,time.Second帮我们封装了秒到纳秒的转换
限速器的实现及分类
漏桶限速器:https://github.com/uber-go/ratelimit
令牌桶限速器:golang/org/x/time/rate
漏桶强调的是恒定速率,比如,一秒漏10个。每次处理请求之前,都判断上次处理的时间,如果小于100ms,则不通过,大于等于100ms,则通过,并更新时间。及时一个小时没有请求了,突然来了两个请求,他们之间也要间隔100ms。一般漏洞都会有一个容器,把请求存起来,然后按照固定的速率处理。
令牌桶则可以累积,如果容量100,在1ms 内来了100个请求,都能通过。