网络流量的限流调整算法

限流算法可以用来保护整个系统的稳定性,防止系统在流量大时被打挂,下面介绍两种常用的两种限流算法 漏桶令牌桶的使用场景以及golang代码实现

漏桶(Leaky_bucket)

漏桶限流算法的原理是以一个恒定的速率从桶里漏出,如果可以注入水中就可以继续服务,如果没有注入水中则就会拒绝服务。它的主要目的是控制流量的速率,平缓一些突发流量,使系统的访问频率按照一个预设的速率进行。
1.png

type RateLimitTb chan struct{}

func NewRatelimitTb(limit int,rate time.Duration) RateLimitTb {
	r := make(chan struct{},limit)
	ticker := time.NewTicker(rate / time.Duration(limit))
	go func() {
		for {
			// 固定的速率取出bucket
			<- r
			// 等待下一次取出的时间
			<- ticker.C
		}
	}()
	return r
}
// 查看是否限制
func (r RateLimitTb)Limit() bool {
	select{
	case r <- struct {}{}:
		return false
	default:
		return true
	}
}




令牌桶(Token_bucket)

漏桶提供了一个很好的平缓突发流量的措施,但是对于一些突发流量,而这些流量还在可控的范围内的话,如果这时再使用漏桶限流,就会出现多余突发的流量被抛弃,但是这些流量系统是有能力处理的,所以此时漏桶限流算法在这里使用是不合适的。而对于这种情况令牌桶算法就比较合适。
令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。

4179645397-5b6e4903ec371_articlex.png

type RateLimit chan struct{}

func NewRateLimit(limit int,rate time.Duration) RateLimit {
	r := make(chan struct{},limit)


	ticker := time.NewTicker(rate / time.Duration(limit))
	go func() {
		for {
			select {
			case r <- struct{}{}:
			default:
			}
			<- ticker.C
		}
	}()
	return r
}
// 查看是否限制
func (r RateLimit)Limit() bool {
	_,ok := <- r
	return ok
}

func TestL2tpStateMon(t *testing.T) {
	r := NewRateLimit(10,time.Second)
	time.Sleep(time.Second * 10)
	for i:=0;i<50;i++ {
		r.Limit()
		fmt.Println("limit status",time.Now().Unix())
		//time.Sleep(time.Millisecond)
	}
}


参考

https://segmentfault.com/a/1190000015967922
https://colobu.com/2014/11/13/rate-limiting/
https://sinchie.com/posts/golang-limit/