最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang官方限流器time/rate的使用與實(shí)現(xiàn)詳解

 更新時(shí)間:2023年04月28日 09:32:55   作者:zhaobuqi  
限流器是后臺(tái)服務(wù)中十分重要的組件,在實(shí)際的業(yè)務(wù)場(chǎng)景中使用居多。time/rate?包基于令牌桶算法實(shí)現(xiàn)限流,本文主要為大家介紹了time/rate的使用與實(shí)現(xiàn),需要的可以參考一下

常見(jiàn)的限流算法

固定窗口計(jì)數(shù)器算法

固定窗口計(jì)數(shù)器算法將時(shí)間分為固定大小的窗口,例如1秒。在每個(gè)窗口中,服務(wù)會(huì)記錄它接收到的請(qǐng)求數(shù)。如果在一個(gè)窗口中的請(qǐng)求數(shù)超過(guò)了預(yù)先設(shè)定的閾值,那么新的請(qǐng)求將被拒絕,直到進(jìn)入下一個(gè)窗口。

這種算法簡(jiǎn)單易實(shí)現(xiàn),但可能會(huì)導(dǎo)致窗口邊界附近的請(qǐng)求突發(fā)。例如,如果窗口大小為1秒,閾值為100,那么在1秒的邊界處,服務(wù)可能會(huì)在短時(shí)間內(nèi)處理200個(gè)請(qǐng)求。

滑動(dòng)窗口計(jì)數(shù)器算法

滑動(dòng)窗口計(jì)數(shù)器算法試圖解決固定窗口計(jì)數(shù)器算法中的請(qǐng)求突發(fā)問(wèn)題。它將窗口分成更小的子窗口,例如將1秒分為10個(gè)100毫秒的子窗口。每次接收到請(qǐng)求時(shí),服務(wù)會(huì)更新當(dāng)前子窗口的計(jì)數(shù)器。服務(wù)會(huì)檢查過(guò)去的N個(gè)子窗口的計(jì)數(shù)器之和,如果這個(gè)和超過(guò)閾值,那么新的請(qǐng)求將被拒絕。

這種算法可以更好地平滑請(qǐng)求流量,但實(shí)現(xiàn)起來(lái)相對(duì)復(fù)雜,因?yàn)樾枰櫠鄠€(gè)子窗口的計(jì)數(shù)器。

令牌桶算法

令牌桶算法維護(hù)一個(gè)令牌桶,其中包含一定數(shù)量的令牌。令牌以恒定速率添加到桶中,直到達(dá)到桶的容量。每次接收到請(qǐng)求時(shí),服務(wù)會(huì)嘗試從桶中獲取一個(gè)令牌。如果桶中有足夠的令牌,請(qǐng)求被允許處理;如果沒(méi)有足夠的令牌,請(qǐng)求將被拒絕。

令牌桶算法允許短暫的請(qǐng)求突發(fā),因?yàn)樵诘土髁繒r(shí)期,令牌可以累積到桶的容量。這種算法在實(shí)踐中表現(xiàn)良好,但實(shí)現(xiàn)起來(lái)相對(duì)復(fù)雜。

漏桶算法

漏桶算法使用一個(gè)隊(duì)列模擬一個(gè)漏水的桶。請(qǐng)求作為水滴進(jìn)入隊(duì)列,以恒定速率從隊(duì)列中移除并處理。如果隊(duì)列已滿(mǎn),新的請(qǐng)求將被拒絕。

漏桶算法可以平滑請(qǐng)求流量,但它不能處理突發(fā)流量,因?yàn)檎?qǐng)求處理速率是固定的。實(shí)現(xiàn)漏桶算法也相對(duì)復(fù)雜,因?yàn)樾枰诤笈_(tái)使用定時(shí)器或其他機(jī)制來(lái)以恒定速率處理隊(duì)列中的請(qǐng)求。

time/rate

主要方法

  • NewLimiter(limit Limit, burst int) *Limiter: 創(chuàng)建一個(gè)新的限流器,參數(shù)包括每秒允許的事件數(shù)量(limit)和令牌桶容量(burst)。
  • (lim *Limiter) Allow() bool: 檢查令牌桶中是否有可用的令牌。如果有可用令牌,則從桶中取走一個(gè)令牌并返回 true;否則返回 false。
  • (lim *Limiter) AllowN(now time.Time, n int) bool: 與 Allow() 類(lèi)似,但檢查 n 個(gè)令牌是否可用。如果有足夠的令牌,從桶中取走 n 個(gè)令牌并返回 true;否則返回 false。
  • (lim *Limiter) Wait(ctx context.Context) error: 阻塞等待,直到有一個(gè)可用的令牌。如果在等待過(guò)程中 context 被取消或超時(shí),將返回一個(gè)錯(cuò)誤。
  • (lim *Limiter) WaitN(ctx context.Context, n int) error: 阻塞等待,直到有 n 個(gè)可用的令牌。如果在等待過(guò)程中 context 被取消或超時(shí),將返回一個(gè)錯(cuò)誤。
  • (lim *Limiter) Reserve() *Reservation: 返回一個(gè)預(yù)留令牌的 Reservation 對(duì)象。你可以根據(jù)需要等待預(yù)留令牌或取消預(yù)留。
  • (lim *Limiter) ReserveN(now time.Time, n int) *Reservation: 類(lèi)似于 Reserve(),但預(yù)留 n 個(gè)令牌。

各個(gè)方法的作用

  • NewLimiter 用于創(chuàng)建一個(gè)新的限流器實(shí)例。
  • Allow 和 AllowN 用于快速檢查是否有足夠的令牌可用,這些方法非阻塞。
  • Wait 和 WaitN 用于阻塞等待直到有足夠的令牌可用,這些方法會(huì)阻塞。
  • Reserve 和 ReserveN 用于預(yù)留令牌,允許您根據(jù)需要等待預(yù)留令牌或取消預(yù)留。

time/rate 是如何實(shí)現(xiàn)限流的

time/rate 包基于令牌桶算法實(shí)現(xiàn)限流。限流器通過(guò)一個(gè)恒定速率(limit)向令牌桶添加令牌,直到桶的容量(burst)達(dá)到上限。每當(dāng)處理一個(gè)請(qǐng)求時(shí),限流器會(huì)嘗試從令牌桶中取出一個(gè)或多個(gè)令牌。

Allow 和 AllowN 方法檢查令牌桶中是否有足夠的令牌。如果沒(méi)有足夠的令牌,這些方法會(huì)立即返回 false,表示應(yīng)拒絕請(qǐng)求。Wait 和 WaitN 方法會(huì)阻塞等待,直到有足夠的令牌可用。如果在等待過(guò)程中上下文(context)被取消或超時(shí),這些方法會(huì)返回一個(gè)錯(cuò)誤,表示請(qǐng)求被拒絕。Reserve 和 ReserveN 方法提供了更靈活的方式來(lái)預(yù)留令牌,您可以根據(jù)需要等待預(yù)留的令牌或取消預(yù)留。

通過(guò)這些方法,time/rate 限流器可以控制處理請(qǐng)求的速率,確保它不會(huì)超過(guò)設(shè)定的限制。通過(guò)調(diào)整令牌生成速率和令牌桶容量,您可以根據(jù)實(shí)際需求和系統(tǒng)負(fù)載來(lái)調(diào)整限流策略。

源碼解析

令牌桶限流器的定義

在 rate.go 文件中,定義了 Limiter 結(jié)構(gòu)體:

type Limiter struct {
    mu     sync.Mutex
    limit  Limit
    tokens float64
    // last 是上次令牌桶更新的時(shí)間
    last time.Time
    // 用于調(diào)整令牌桶更新時(shí)間的時(shí)鐘
    clock Clock
    // 用于在 Wait 系列方法中進(jìn)行休眠的定時(shí)器
    sleepFn func(time.Duration)
}

Limiter 結(jié)構(gòu)體包含了一些關(guān)鍵屬性,例如令牌生成速率(limit)、當(dāng)前令牌數(shù)(tokens)和上次更新時(shí)間(last)。

令牌桶更新

time/rate 包中的核心函數(shù)之一是 reserveN,它負(fù)責(zé)預(yù)留 N 個(gè)令牌。在此過(guò)程中,令牌桶會(huì)根據(jù)時(shí)間更新。

func (lim *Limiter) reserveN(now time.Time, n int) *Reservation {
    lim.mu.Lock()
    defer lim.mu.Unlock()
    // 更新令牌桶
    now, tokens := lim.advance(now)
    // 計(jì)算需要的令牌數(shù)與當(dāng)前可用令牌數(shù)之間的差值
    delta := float64(n) - tokens
    // 計(jì)算等待時(shí)間
    waitDuration := lim.limit.durationFromTokens(delta)
    // 更新令牌桶狀態(tài)
    tokens -= float64(n)
    lim.last = now.Add(waitDuration)
    lim.tokens = tokens
    return &Reservation{
        ok:        true,
        lim:       lim,
        tokens:    n,
        timeToAct: now.Add(waitDuration),
    }
}

在 reserveN 函數(shù)中,首先調(diào)用 advance 函數(shù)來(lái)更新令牌桶:

func (lim *Limiter) advance(now time.Time) (time.Time, float64) {
    last := lim.last
    // 計(jì)算上次更新以來(lái)經(jīng)過(guò)的時(shí)間
    elapsed := now.Sub(last)
    // 根據(jù)經(jīng)過(guò)的時(shí)間計(jì)算生成的令牌數(shù)
    delta := elapsed.Seconds() * float64(lim.limit)
    // 更新令牌桶中的令牌數(shù),但不超過(guò)令牌桶容量
    tokens := math.Min(lim.tokens+delta, float64(lim.limit.Burst()))
    return now, tokens
}

advance 函數(shù)根據(jù)時(shí)間更新令牌桶,計(jì)算從上次更新以來(lái)生成的令牌數(shù)量,并將新令牌添加到桶中,但不超過(guò)桶的容量。

令牌預(yù)留和等待

在 reserveN 函數(shù)中,首先計(jì)算需要的令牌數(shù)與當(dāng)前可用令牌數(shù)之間的差值。然后根據(jù)差值計(jì)算等待時(shí)間。如果等待時(shí)間為正值,則表示需要等待一段時(shí)間

才能獲得足夠的令牌。最后,更新令牌桶狀態(tài),將所需令牌數(shù)從當(dāng)前令牌數(shù)中減去。

reserveN 函數(shù)返回一個(gè) Reservation 對(duì)象,其中包含預(yù)留的令牌數(shù)、等待時(shí)間等信息。Reservation 結(jié)構(gòu)體定義如下:

type Reservation struct {
    ok        bool
    lim       *Limiter
    tokens    int
    timeToAct time.Time
}

Reservation 對(duì)象提供了一些方法,例如 Delay(返回需要等待的時(shí)間)和 Cancel(取消預(yù)留)。這些方法允許用戶(hù)在需要時(shí)等待預(yù)留的令牌,或在不再需要令牌時(shí)取消預(yù)留。

公開(kāi) API

time/rate 包提供了一系列公開(kāi) API,例如 AllowAllowNWaitWaitNReserve 和 ReserveN。這些方法都是基于 reserveN 函數(shù)的封裝。例如,Allow 方法只需檢查預(yù)留的等待時(shí)間是否為零:

func (lim *Limiter) Allow() bool {
    return lim.AllowN(time.Now(), 1)
}
func (lim *Limiter) AllowN(now time.Time, n int) bool {
    return lim.reserveN(now, n).Delay() == 0
}

類(lèi)似地,Wait 和 WaitN 方法將阻塞等待,直到預(yù)留的等待時(shí)間過(guò)去:

func (lim *Limiter) Wait(ctx context.Context) error {
    return lim.WaitN(ctx, 1)
}
func (lim *Limiter) WaitN(ctx context.Context, n int) error {
    if n > lim.limit.Burst() {
        return fmt.Errorf("rate: Wait(n=%d) exceeds limiter's burst %d", n, lim.limit.Burst())
    }
    r := lim.ReserveN(time.Now(), n)
    delay := r.DelayFrom(time.Now())
    if delay == 0 {
        return nil
    }
    t := lim.clock.AfterFunc(delay, r.Cancel)
    defer t.Stop()
    select {
    case <-ctx.Done():
        r.Cancel()
        return ctx.Err()
    case <-t.C:
        return nil
    }
}

總之,time/rate 包通過(guò)令牌桶算法實(shí)現(xiàn)了限流。它提供了一系列 API,允許用戶(hù)在不同場(chǎng)景下靈活地控制請(qǐng)求速率。內(nèi)部實(shí)現(xiàn)主要依賴(lài)于 reserveN 函數(shù)來(lái)更新令牌桶狀態(tài),并根據(jù)需要等待或預(yù)留令牌。

到此這篇關(guān)于Golang官方限流器time/rate的使用與實(shí)現(xiàn)詳解的文章就介紹到這了,更多相關(guān)Golang限流器time/rate內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go整合ElasticSearch的示例代碼

    Go整合ElasticSearch的示例代碼

    這篇文章主要介紹了Go整合ElasticSearch的相關(guān)知識(shí),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-07-07
  • 淺談golang fasthttp踩坑經(jīng)驗(yàn)

    淺談golang fasthttp踩坑經(jīng)驗(yàn)

    本文主要介紹了golang fasthttp踩坑經(jīng)驗(yàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • golang中數(shù)組與切片的區(qū)別詳析

    golang中數(shù)組與切片的區(qū)別詳析

    數(shù)組是固定長(zhǎng)度,常量,切片長(zhǎng)度是可以改變,所以是一個(gè)可變的數(shù)組,下面這篇文章主要給大家介紹了關(guān)于golang中數(shù)組與切片區(qū)別的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-11-11
  • Go設(shè)置http請(qǐng)求超時(shí)的方法實(shí)現(xiàn)

    Go設(shè)置http請(qǐng)求超時(shí)的方法實(shí)現(xiàn)

    這篇文章主要介紹了Go設(shè)置http請(qǐng)求超時(shí)的方法實(shí)現(xiàn),最近接手了一個(gè)老項(xiàng)目進(jìn)行維護(hù),發(fā)現(xiàn)其中有個(gè)關(guān)于 http 請(qǐng)求的方法設(shè)置的 timeout 沒(méi)有生效,很奇怪,一開(kāi)始查看代碼并沒(méi)有發(fā)現(xiàn)什么可疑點(diǎn),后查看了源碼,打斷點(diǎn)調(diào)試才發(fā)現(xiàn)問(wèn)題所在,這里簡(jiǎn)單記錄復(fù)盤(pán)一下
    2024-08-08
  • Go中Channel發(fā)送和接收操作指南

    Go中Channel發(fā)送和接收操作指南

    在golang中channel屬于較為核心的一個(gè)功能,尤其在go協(xié)程中,channel功能尤為重要,下面這篇文章主要給大家介紹了關(guān)于Go中Channel發(fā)送和接收操作的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • golang進(jìn)程在docker中OOM后hang住問(wèn)題解析

    golang進(jìn)程在docker中OOM后hang住問(wèn)題解析

    這篇文章主要介紹了golang進(jìn)程在docker中OOM后hang住問(wèn)題解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • gin自定義中間件解決requestBody不可重讀(請(qǐng)求體取值)

    gin自定義中間件解決requestBody不可重讀(請(qǐng)求體取值)

    這篇文章主要介紹了gin自定義中間件解決requestBody不可重讀,確??刂破髂軌颢@取請(qǐng)求體值,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • Go 控制協(xié)程(goroutine)的并發(fā)數(shù)量

    Go 控制協(xié)程(goroutine)的并發(fā)數(shù)量

    控制協(xié)程goroutine的并發(fā)數(shù)量是一個(gè)常見(jiàn)的需求,本文就來(lái)介紹一下Go 控制協(xié)程的并發(fā)數(shù)量,具有一定的參考價(jià)值,感興趣的可以了解一下
    2025-02-02
  • go語(yǔ)言實(shí)現(xiàn)依賴(lài)注入的示例代碼

    go語(yǔ)言實(shí)現(xiàn)依賴(lài)注入的示例代碼

    依賴(lài)注入和控制反轉(zhuǎn)恰恰相反,它是一種具體的編碼技巧,我們不通過(guò) new 的方式在類(lèi)內(nèi)部創(chuàng)建依賴(lài)類(lèi)的對(duì)象,而是將依賴(lài)的類(lèi)對(duì)象在外部創(chuàng)建好之后,通過(guò)構(gòu)造函數(shù)、函數(shù)參數(shù)等方式傳遞給類(lèi)來(lái)使用,本文將給大家介紹go語(yǔ)言實(shí)現(xiàn)依賴(lài)注入,需要的朋友可以參考下
    2024-01-01
  • Golang channel關(guān)閉的實(shí)現(xiàn)示例

    Golang channel關(guān)閉的實(shí)現(xiàn)示例

    channel關(guān)閉不當(dāng)或不關(guān)閉會(huì)引發(fā)很多問(wèn)題,本文主要介紹了Golang channel關(guān)閉的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01

最新評(píng)論

华宁县| 广汉市| 怀柔区| 惠东县| 大城县| 察雅县| 华亭县| 昭觉县| 武隆县| 阳西县| 大新县| 荆门市| 利川市| 松溪县| 天柱县| 留坝县| 兴义市| 玉溪市| 漳浦县| 高安市| 定远县| 富裕县| 鄂尔多斯市| 阳城县| 凤翔县| 翁源县| 锡林浩特市| 阳新县| 交城县| 象州县| 永康市| 历史| 广安市| 汨罗市| 塘沽区| 毕节市| 越西县| 历史| 同仁县| 巴彦县| 马关县|