If ❤️ my article is helpful, welcome to like, follow. This is the biggest encouragement for me to continue my technical creation.
This article is a series of articles to deal with sudden traffic, and the following are related to gay friends
- In the face of burst traffic: system and software layer traffic limiting methods
- Program level flow limiting – necessity
- Program Level Current Limiting – Graphic realization of four current limiting methods (Golang version)
Counter current limiting
package main
import (
"fmt"
"sync"
"time"
)
type RequestLimiter struct {
Interval time.Duration // recount the time
MaxCount int // Maximum count
Lock sync.Mutex
ReqCount int // Current number of requests
}
func (reqLimiter *RequestLimiter) IsAvailable(a) bool {
reqLimiter.Lock.Lock()
defer reqLimiter.Lock.Unlock()
return reqLimiter.ReqCount < reqLimiter.MaxCount
}
/ / non-blocking
func (reqLimiter *RequestLimiter) AddRequestCount(a) bool {
reqLimiter.Lock.Lock()
defer reqLimiter.Lock.Unlock()
if reqLimiter.ReqCount < reqLimiter.MaxCount {
reqLimiter.ReqCount += 1
return true
}
return false
}
func NewRequestLimitService(interval time.Duration, maxCount int) *RequestLimiter {
reqLimit := &RequestLimiter{
Interval: interval,
MaxCount: maxCount,
}
go func(a) {
ticker := time.NewTicker(interval)
for true {
<-ticker.C
reqLimit.Lock.Lock()
fmt.Println("reset Count ...")
reqLimit.ReqCount = 0
reqLimit.Lock.Unlock()
}
}()
return reqLimit
}
/ * * principle: Ticker := time.newticker (2* time.second) for {currentTime := < -ticker.c FMT.Println(" currentTime :", currentTime)} output: currentTime: 2021-05-19 11:02:12.3603475 +0800 CST m=+2.002147201 currentTime: 2021-05-19 11:02:14.3611806 +0800 CST m=+4.002980301 Current time: 2021-05-19 11:02:16.360625 +0800 CST m=+6.002424701 */
func main(a) {
service := NewRequestLimitService(time.Second, 2)
for true {
hasToken := service.AddRequestCount()
if hasToken {
fmt.Println(time.Now())
}
}
}
Copy the code
The sliding window
package main
import (
"fmt"
"sync"
"time"
)
type WindowLimiter struct {
Interval time.Duration // Total time
WinCount []int // The number of accesses per window
TicketSize int // Maximum window capacity
TicketCount int // Number of Windows
Lock sync.Mutex
CurIndex int // Which window is currently in use
}
func (reqLimiter *WindowLimiter) IsAvailable(a) bool {
reqLimiter.Lock.Lock()
defer reqLimiter.Lock.Unlock()
return reqLimiter.WinCount[reqLimiter.CurIndex] < reqLimiter.TicketSize
}
func (reqLimiter *WindowLimiter) AddRequestCount(a) bool {
reqLimiter.Lock.Lock()
defer reqLimiter.Lock.Unlock()
if reqLimiter.WinCount[reqLimiter.CurIndex] < reqLimiter.TicketSize {
reqLimiter.WinCount[reqLimiter.CurIndex]++
return true
}
return false
}
func NewRequestLimitService(interval time.Duration, ticketCount int, ticketSize int) *WindowLimiter {
reqLimit := &WindowLimiter{
Interval: interval,
WinCount: make([]int, ticketCount, ticketCount),
TicketSize: ticketSize,
TicketCount: ticketCount,
CurIndex: 0,}go func(a) {
ticker := time.NewTicker(time.Duration(interval.Nanoseconds() / int64(ticketCount)))
for true {
<-ticker.C
reqLimit.Lock.Lock()
reqLimit.CurIndex = (reqLimit.CurIndex + 1) % reqLimit.TicketCount
reqLimit.WinCount[reqLimit.CurIndex] = 0
fmt.Println("reset Count ...")
reqLimit.Lock.Unlock()
}
}()
return reqLimit
}
func main(a) {
service := NewRequestLimitService(time.Second, 2.1)
for true {
hasToken := service.AddRequestCount()
if hasToken {
fmt.Println(time.Now())
}
}
}
Copy the code
Bucket algorithm
package main
import (
"fmt"
"math"
"sync"
"time"
)
type BucketLimiter struct {
Timestamp time.Time // The timestamp of the current water injection
Capacity float64 // The capacity of a bucket
Rate float64 / / speed
Water float64 // The current amount of water
Lock sync.Mutex
}
func AddWater(bucket *BucketLimiter) bool {
now := time.Now()
leftWater := math.Max(0, bucket.Water-now.Sub(bucket.Timestamp).Seconds()*bucket.Rate)
bucket.Lock.Lock()
defer bucket.Lock.Unlock()
if leftWater+1 < bucket.Capacity {
// Try adding water, the bucket is not full
bucket.Timestamp = now
bucket.Water = leftWater + 1
return true
} else {
// Access denied when water is full
return false}}func main(a) {
service := &BucketLimiter{
Timestamp: time.Now(),
Capacity: 2,
Rate: 1,
Water: 0,}for true {
hasToken := AddWater(service)
if hasToken {
fmt.Println(time.Now())
}
}
}
Copy the code
Token bucket algorithm
package main
import (
"math"
"sync"
"time"
)
// Define the token bucket structure
type tokenBucket struct {
timestamp time.Time // The current timestamp
capacity float64 // Bucket capacity (maximum number of tokens)
rate float64 // Token loading speed
tokens float64 // Total number of current tokens
lock sync.Mutex
}
// Determine whether to obtain the token (if so, process the request)
func getToken(bucket tokenBucket) bool {
now := time.Now()
bucket.lock.Lock()
defer bucket.lock.Unlock()
// Add the token first
leftTokens := math.Max(bucket.capacity, bucket.tokens+now.Sub(bucket.timestamp).Seconds()*bucket.rate)
if leftTokens < 1 {
// If there is no token in the bucket, reject it
return false
} else {
// There is a token in the bucket
bucket.tokens -= 1
bucket.timestamp = now
return true}}Copy the code