mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
Update code to use Go 1.0 types and conventions. Remove rate limiting package code and instead direct users to search godoc.org for such packages.
parent
1b8b1f9159
commit
da391aa637
130
RateLimiting.md
130
RateLimiting.md
@ -1,14 +1,15 @@
|
||||
# Rate Limiting
|
||||
|
||||
## Time Tick based Approach
|
||||
|
||||
To limit the rate of operations per unit time, use time.Tick:
|
||||
To limit the rate of operations per unit time, use a [time.Ticker](http://golang.org/pkg/time/#NewTicker).
|
||||
This works well for rates up to 10s per second.
|
||||
For higher rates, prefer a token bucket rate limiter (search godoc.org for
|
||||
[rate limit](http://godoc.org/?q=rate+limit)).
|
||||
|
||||
```go
|
||||
import "time"
|
||||
|
||||
rate_per_sec := 10
|
||||
throttle := time.Tick(1e9 / rate_per_sec)
|
||||
ratePerSec := 10
|
||||
throttle := time.Tick(1e9 / ratePerSec)
|
||||
for req := range requests {
|
||||
<-throttle // rate limit our Service.Method RPCs
|
||||
go client.Call("Service.Method", req, ...)
|
||||
@ -19,15 +20,15 @@ To allow some bursts, add a buffer to the throttle:
|
||||
```go
|
||||
import "time"
|
||||
|
||||
rate_per_sec := 10
|
||||
burst_limit := 100
|
||||
tick := time.NewTicker(1e9 / rate_per_sec)
|
||||
ratePerSec := 10
|
||||
burstLimit := 100
|
||||
tick := time.NewTicker(1e9 / ratePerSec)
|
||||
defer tick.Stop()
|
||||
throttle := make(chan int64, burst_limit)
|
||||
throttle := make(chan time.Time, burstLimit)
|
||||
go func() {
|
||||
for ns := range tick {
|
||||
for t := range tick {
|
||||
select {
|
||||
case: throttle <- ns
|
||||
case: throttle <- t
|
||||
default:
|
||||
}
|
||||
} // exits after tick.Stop()
|
||||
@ -37,110 +38,3 @@ for req := range requests {
|
||||
go client.Call("Service.Method", req, ...)
|
||||
}
|
||||
```
|
||||
|
||||
## Simpler Approach that doesn't need channels or go routines
|
||||
|
||||
Here is a simpler approach that relies on the notion of elapsed time to provide rate control. It is implemented as a package so others can readily use it.
|
||||
|
||||
|
||||
|
||||
```go
|
||||
//
|
||||
// Ratelimiting incoming connections - Small Library
|
||||
//
|
||||
// (c) 2013 Sudhi Herle <sudhi-dot-herle-at-gmail-com>
|
||||
//
|
||||
// License: GPLv2
|
||||
//
|
||||
// Notes:
|
||||
// - This is a very simple interface for rate limiting. It
|
||||
// implements a token bucket algorithm
|
||||
// - Based on Anti Huimaa's very clever token bucket algorithm.
|
||||
//
|
||||
// Usage:
|
||||
// rl = NewRateLimiter(rate)
|
||||
//
|
||||
// ....
|
||||
// if rl.Limit() {
|
||||
// drop_connection(conn)
|
||||
// }
|
||||
//
|
||||
package ratelimit
|
||||
|
||||
import "time"
|
||||
|
||||
type Ratelimiter struct {
|
||||
rate int // conn/sec
|
||||
last time.Time // last time we were polled/asked
|
||||
|
||||
allowance float64
|
||||
}
|
||||
|
||||
// Create new rate limiter that limits at rate/sec
|
||||
func NewRateLimiter(rate int) (*Ratelimiter, error) {
|
||||
|
||||
r := Ratelimiter{rate: rate, last: time.Now()}
|
||||
|
||||
r.allowance = float64(r.rate)
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
// Return true if the current call exceeds the set rate, false
|
||||
// otherwise
|
||||
func (r *Ratelimiter) Limit() bool {
|
||||
|
||||
// handle cases where rate in config file is unset - defaulting
|
||||
// to "0" (unlimited)
|
||||
if r.rate == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
rate := float64(r.rate)
|
||||
now := time.Now()
|
||||
elapsed := now.Sub(r.last)
|
||||
r.last = now
|
||||
r.allowance += elapsed.Seconds() * rate
|
||||
|
||||
// Clamp number of tokens in the bucket. Don't let it get
|
||||
// unboundedly large
|
||||
if r.allowance > rate {
|
||||
r.allowance = rate
|
||||
}
|
||||
|
||||
var ret bool
|
||||
|
||||
if r.allowance < 1.0 {
|
||||
ret = true
|
||||
} else {
|
||||
r.allowance -= 1.0
|
||||
ret = false
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
```
|
||||
|
||||
Using this package is quite easy:
|
||||
|
||||
```go
|
||||
// rate limit at 100/s
|
||||
nl = ratelimit.NewRateLimiter(100)
|
||||
|
||||
....
|
||||
// in your event loop or network accept loop, do:
|
||||
if rl.Limit() {
|
||||
// drop the connection etc.
|
||||
// i.e., this new event has exceeded the rate of 100/s
|
||||
...
|
||||
}
|
||||
else {
|
||||
// .. rate is not exceeded, process as needed
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
[Anti Huimaa](http://stackoverflow.com/questions/667508/whats-a-good-rate-limiting-algorithm) came up with this simple algorithm.
|
||||
|
||||
# References
|
||||
|
||||
time.Tick: http://golang.org/pkg/time/#Tick
|
Loading…
x
Reference in New Issue
Block a user