真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

常見的限流算法

限流

通過限制并發(fā)訪問數(shù)或者限制一個(gè)時(shí)間窗口內(nèi)允許處理的請求數(shù)量來保護(hù)系統(tǒng),例如,通過限流,你可以過濾掉產(chǎn)生流量峰值的客戶和服務(wù)。

成都創(chuàng)新互聯(lián)公司成立十多年來,這條路我們正越走越好,積累了技術(shù)與客戶資源,形成了良好的口碑。為客戶提供成都網(wǎng)站制作、成都網(wǎng)站建設(shè)、外貿(mào)營銷網(wǎng)站建設(shè)、網(wǎng)站策劃、網(wǎng)頁設(shè)計(jì)、域名注冊、網(wǎng)絡(luò)營銷、VI設(shè)計(jì)、網(wǎng)站改版、漏洞修補(bǔ)等服務(wù)。網(wǎng)站是否美觀、功能強(qiáng)大、用戶體驗(yàn)好、性價(jià)比高、打開快等等,這些對于網(wǎng)站建設(shè)都非常重要,成都創(chuàng)新互聯(lián)公司通過對建站技術(shù)性的掌握、對創(chuàng)意設(shè)計(jì)的研究為客戶提供一站式互聯(lián)網(wǎng)解決方案,攜手廣大客戶,共同發(fā)展進(jìn)步。

令牌桶算法

令牌桶算法是常見的一種限流算法。假設(shè)有一個(gè)桶,以固定速度(rate)往桶里加入令牌(token)。當(dāng)桶滿了時(shí)停止加入。服務(wù)收到請求時(shí)嘗試從桶里取出令牌。如果成功取出,則可以響應(yīng)本次請求。如果沒有取到,可以進(jìn)行有限時(shí)間的等待或者返回超時(shí)錯(cuò)誤。

特點(diǎn)

遇到流量洪峰時(shí)可以應(yīng)對部分突發(fā)流量,但由于桶有容量上限,當(dāng)消耗完桶里堆積的令牌之后只能根據(jù)令牌的生成速率提供服務(wù),從而起到限流的作用。

Golang 實(shí)現(xiàn)

Golang rate包提供了 token limiter 的實(shí)現(xiàn),具體可以點(diǎn)擊鏈接查看rate package

漏桶算法

一個(gè)固定容量的漏桶,按照常量固定速率流出水滴,這里的水滴指的就是能進(jìn)行響應(yīng)的請求。當(dāng)漏桶滿了時(shí),請求就會被丟棄,返回一個(gè)限流標(biāo)志。

特點(diǎn)

流量均勻,一般作為計(jì)量工具,可以用于流量整形和流量控制。比方說對數(shù)據(jù)庫的操作。經(jīng)過一層漏桶控制,可以有效控制對數(shù)據(jù)庫的請求,避免數(shù)據(jù)庫被打掛。流量穩(wěn)定,但是無法應(yīng)對突發(fā)流量。

Golang 實(shí)現(xiàn)

uber 開源了一個(gè)基于漏桶的限流器ratelimit

func main() {
	rl := ratelimit.New(1) // per second
	for i := 0; i < 10; i++ {
		now := rl.Take()
		if i > 0 {
			fmt.Println(i, now)
		}
	}
}

1 2022-03-24 02:24:51. 
2 2022-03-24 02:24:52. 
3 2022-03-24 02:24:53. 
4 2022-03-24 02:24:54. 
5 2022-03-24 02:24:55. 
6 2022-03-24 02:24:56. 
7 2022-03-24 02:24:57. 
8 2022-03-24 02:24:58. 
9 2022-03-24 02:24:59. 

可以看到,通過“漏桶”這層的過濾,可以有效保護(hù)我們的服務(wù)。

// WithoutSlack configures the limiter to be strict and not to accumulate
// previously "unspent" requests for future bursts of traffic.
var WithoutSlack Option = slackOption(0)

// WithSlack configures custom slack.
// Slack allows the limiter to accumulate "unspent" requests
// for future bursts of traffic.
func WithSlack(slack int) Option {
	return slackOption(slack)
}

可以簡單對比一下

rl := ratelimit.New(1, ratelimit.WithoutSlack) // per second
for i := 0; i < 10; i++ {
	now := rl.Take()
	if i == 2 {
		time.Sleep(2 * time.Second)
	}
	if i > 0 {
		fmt.Println(i, now)
	}
}
1 2022-03-24 02:34:22. 
2 2022-03-24 02:34:23.   //sleep 2 秒,后面 rps 還是很平穩(wěn)
3 2022-03-24 02:34:25. 
4 2022-03-24 02:34:26. 
5 2022-03-24 02:34:27. 
6 2022-03-24 02:34:28. 
7 2022-03-24 02:34:29. 
8 2022-03-24 02:34:30. 
9 2022-03-24 02:34:31. 

rl := ratelimit.New(1, ratelimit.WithSlack(5)) // per second
for i := 0; i < 10; i++ {
	now := rl.Take()
	if i == 2 {
		time.Sleep(5 * time.Second)
	}
	if i > 0 {
		fmt.Println(i, now)
	}
}
1 2022-03-24 02:39:58. 
2 2022-03-24 02:39:59.  //sleep 5 秒,這里的例子比較夸張,不過可看到我們可以一次性處理 5 個(gè)
3 2022-03-24 02:40:04. 
4 2022-03-24 02:40:04. 
5 2022-03-24 02:40:04. 
6 2022-03-24 02:40:04. 
7 2022-03-24 02:40:04. 
8 2022-03-24 02:40:05. 
9 2022-03-24 02:40:06. 

我們?nèi)〉每梢蕴幚淼恼埱蠛筮€應(yīng)該結(jié)合 context 上下午中的上下文時(shí)間,避免拿到請求后處理請求超時(shí)。

滑動(dòng)窗口算法

滑動(dòng)窗口算法是對普通時(shí)間窗口計(jì)數(shù)的優(yōu)化,我們知道普通時(shí)間窗口計(jì)數(shù)存在精度的不足,比如說我們服務(wù)1秒可以處理1000個(gè)請求,所以這里我們限制1s處理的請求數(shù)為1000。前1秒后500ms 來了600個(gè)請求,后一秒前400ms 來了600個(gè)請求,那么在這 900ms的間隔里就來了1200 個(gè)請求。主要的原因就在于普通時(shí)間窗口計(jì)數(shù)每間隔 1 s 會刷新,所以滑動(dòng)窗口將間隔時(shí)間劃分為多個(gè)區(qū)間,從設(shè)計(jì)上優(yōu)化了精度問題。

Golang 實(shí)現(xiàn)

type slot struct {
	startTime time.Time //slot 的起始時(shí)間
	count     int       //數(shù)量
}

type slots []*slot

type window slots //窗口

func sumReq(win window) int { //計(jì)數(shù)
	count := 0
	for _, slot := range win {
		count += slot.count
	}
	return count
}

type RollingWindow struct {
	slotLength time.Duration //slot 的長度
	slotNum    int           //slot 個(gè)數(shù)
	winLenght  time.Duration //窗口長度
	maxReqNum  int           //rolling window 內(nèi)允許的最大請求書
	win        window        //窗口
	lock       sync.Mutex    //鎖
}

func NewRollingWindow(slotLength time.Duration, slotNum int, maxReqNum int) *RollingWindow {
	return &RollingWindow{
		slotLength: slotLength,
		slotNum:    slotNum,
		winLenght:  slotLength * time.Duration(slotNum),
		maxReqNum:  maxReqNum,
		win:        make(window, 0, slotNum),
		lock:       sync.Mutex{},
	}
}

func (rw *RollingWindow) IsLimit() bool {
	return !rw.validate()
}


func (rw *RollingWindow) validate() bool {
	now := time.Now()
	rw.lock.Lock()
	defer rw.lock.Unlock()
	//滑動(dòng)窗口
	rw = rw.slideRight(now)
	//是否超限
	can := rw.accept()
	if can {
		//記錄請求數(shù)
		rw.update(now)
	}

	return can
}

//向右移動(dòng)窗口 [0,1,2,3,4,5] -> [1,2,3,4,5]
func (rw *RollingWindow) slideRight(now time.Time) *RollingWindow {
	offset := -1
	for i, slot := range rw.win {
		if slot.startTime.Add(rw.winLenght).After(now) {
			break //不需要滑動(dòng)
		}
		offset = i
	}
	if offset > -1 {
		rw.win = rw.win[offset+1:]
	}
	return rw
}

//判斷請求是否超限 沒有超限返回 true
func (rw *RollingWindow) accept() bool {
	return sumReq(rw.win) < rw.maxReqNum
}

func (rw *RollingWindow) update(now time.Time) *RollingWindow {

	if len(rw.win) > 0 {
		lastOffset := len(rw.win) - 1
		lastSlot := rw.win[lastOffset]
		if lastSlot.startTime.Add(rw.slotLength).Before(now) {
			//填入新的 slot
			newSlot := &slot{startTime: now, count: 1}
			rw.win = append(rw.win, newSlot)
		} else {
			rw.win[lastOffset].count++
		}
	} else {
		newSlot := &slot{startTime: now, count: 1}
		rw.win = append(rw.win, newSlot)
	}

	return rw
}

func main() {
	l := NewRollingWindow(100*time.Millisecond, 10, 10)
	fakeDealReq(l, 3)
	printRollingWindow(l)
	time.Sleep(200 * time.Millisecond)

	fakeDealReq(l, 3)
	printRollingWindow(l)

	time.Sleep(200 * time.Millisecond)
	fakeDealReq(l, 5)
	printRollingWindow(l)

	time.Sleep(1 * time.Second)
	fakeDealReq(l, 1)
	printRollingWindow(l)
}

func fakeDealReq(l *RollingWindow, num int) {
	for i := 0; i < num; i++ {
		fmt.Println(l.IsLimit())
	}
}

func printRollingWindow(l *RollingWindow) {
	for _, v := range l.win {
		fmt.Println(v.startTime, v.count)
	}
}

//輸出
false
false
false
2022-03-24 05:06:04. +0000 UTC m=+0.0000 3
false
false
false
2022-03-24 05:06:04. +0000 UTC m=+0.0000 3
2022-03-24 05:06:04. +0000 UTC m=+0. 3
false
false
false
false
true
2022-03-24 05:06:04. +0000 UTC m=+0.0000 3
2022-03-24 05:06:04. +0000 UTC m=+0. 3
2022-03-24 05:06:05.0 +0000 UTC m=+0. 4
false
2022-03-24 05:06:06.0 +0000 UTC m=+1. 1


本文題目:常見的限流算法
網(wǎng)頁地址:http://weahome.cn/article/dsoicpg.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部