欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Golang 限流器的使用和實(shí)現(xiàn)示例

 更新時(shí)間:2020年06月28日 10:56:41   作者:搬磚程序員帶你飛  
這篇文章主要介紹了Golang 限流器的使用和實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

限流器是服務(wù)中非常重要的一個(gè)組件,在網(wǎng)關(guān)設(shè)計(jì)、微服務(wù)、以及普通的后臺(tái)應(yīng)用中都比較常見。它可以限制訪問服務(wù)的頻次和速率,防止服務(wù)過載,被刷爆。

限流器的算法比較多,常見的比如令牌桶算法、漏斗算法、信號量等。本文主要介紹基于漏斗算法的一個(gè)限流器的實(shí)現(xiàn)。文本也提供了其他幾種開源的實(shí)現(xiàn)方法。

基于令牌桶的限流器實(shí)現(xiàn)

在golang 的官方擴(kuò)展包 time 中(github/go/time),提供了一個(gè)基于令牌桶算法的限流器的實(shí)現(xiàn)。

原理

令牌桶限流器,有兩個(gè)概念:

  • 令牌:每次都需要拿到令牌后,才可以訪問
  • 桶:有一定大小的桶,桶中最多可以放一定數(shù)量的令牌
  • 放入頻率:按照一定的頻率向通里面放入令牌,但是令牌數(shù)量不能超過桶的容量

因此,一個(gè)令牌桶的限流器,可以限制一個(gè)時(shí)間間隔內(nèi),最多可以承載桶容量的訪問頻次。下面我們看看官方的實(shí)現(xiàn)。

實(shí)現(xiàn)

限流器的定義

下面是對一個(gè)限流器的定義:

type Limiter struct {
 limit Limit // 放入桶的頻率  (Limit 為 float64類型)
 burst int  // 桶的大小

 mu   sync.Mutex
 tokens float64 // 當(dāng)前桶內(nèi)剩余令牌個(gè)數(shù)
 last time.Time // 最近取走token的時(shí)間
 lastEvent time.Time // 最近限流事件的時(shí)間
}

其中,核心參數(shù)是 limit,burst。 burst 代表了桶的大小,從實(shí)際意義上來講,可以理解為服務(wù)可以承載的并發(fā)量大?。籰imit 代表了 放入桶的頻率,可以理解為正常情況下,1s內(nèi)我們的服務(wù)可以處理的請求個(gè)數(shù)。

在令牌發(fā)放后,會(huì)被保留在Reservation 對象中,定義如下:

type Reservation struct {
 ok    bool // 是否滿足條件分配到了tokens
 lim    *Limiter // 發(fā)送令牌的限流器
 tokens  int  // tokens 的數(shù)量
 timeToAct time.Time // 滿足令牌發(fā)放的時(shí)間
 limit Limit // 令牌發(fā)放速度
}

Reservation 對象,描述了一個(gè)在達(dá)到 timeToAct 時(shí)間后,可以獲取到的令牌的數(shù)量tokens。 (因?yàn)橛行┬枨髸?huì)做預(yù)留的功能,所以timeToAct 并不一定就是當(dāng)前的時(shí)間。

限流器如何限流

官方提供的限流器有阻塞等待式的,也有直接判斷方式的,還有提供了自己維護(hù)預(yù)留式的,但核心的實(shí)現(xiàn)都是下面的reserveN 方法。

// 在 now 時(shí)間需要拿到n個(gè)令牌,最多可以等待的時(shí)間為maxFutureResrve
// 結(jié)果將返回一個(gè)預(yù)留令牌的對象
func (lim *Limiter) reserveN(now time.Time, n int, maxFutureReserve time.Duration) Reservation {
 lim.mu.Lock()

 // 首先判斷是否放入頻次是否為無窮大,如果為無窮大,說明暫時(shí)不限流
 if lim.limit == Inf {
  // ...
 }

 // 拿到截至now 時(shí)間時(shí),可以獲取的令牌tokens數(shù)量,上一次拿走令牌的時(shí)間last
 now, last, tokens := lim.advance(now)

 // 然后更新 tokens 的數(shù)量,把需要拿走的去掉
 tokens -= float64(n)

 // 如果tokens 為負(fù)數(shù),說明需要等待,計(jì)算等待的時(shí)間
 var waitDuration time.Duration
 if tokens < 0 {
  waitDuration = lim.limit.durationFromTokens(-tokens)
 }

 // 計(jì)算是否滿足分配條件
 // ① 需要分配的大小不超過桶容量
 // ② 等待時(shí)間不超過設(shè)定的等待時(shí)常
 ok := n <= lim.burst && waitDuration <= maxFutureReserve

 // 最后構(gòu)造一個(gè)Reservation對象
 r := Reservation{
  ok:  ok,
  lim:  lim,
  limit: lim.limit,
 }
 if ok {
  r.tokens = n
  r.timeToAct = now.Add(waitDuration)
 }

 // 并更新當(dāng)前l(fā)imiter 的值
 if ok {
  lim.last = now
  lim.tokens = tokens
  lim.lastEvent = r.timeToAct
 } else {
  lim.last = last
 }

 lim.mu.Unlock()
 return r
}

從實(shí)現(xiàn)上看,limiter 并不是每隔一段時(shí)間更新當(dāng)前桶中令牌的數(shù)量,而是記錄了上次訪問時(shí)間和當(dāng)前桶中令牌的數(shù)量。當(dāng)再次訪問時(shí),通過上次訪問時(shí)間計(jì)算出當(dāng)前桶中的令牌的數(shù)量,決定是否可以發(fā)放令牌。

使用

下面我們通過一個(gè)簡單的例子,學(xué)習(xí)上面介紹的限流器的使用。

 limiter := rate.NewLimiter(rate.Every(100*time.Millisecond), 10)
 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  if limiter.Allow() {// do something
   log.Println("say hello")
  }
 })
 _ = http.ListenAndServe(":13100", nil)

上面,每100 ms 放入令牌桶中1個(gè)令牌,所以當(dāng)批量訪問該接口時(shí),可以看到如下結(jié)果:

2020/06/26 14:34:16 say hello  有18 條記錄
2020/06/26 14:34:17 say hello  有10 條記錄
2020/06/26 14:34:18 say hello  有10 條記錄
  ...

一開始漏斗滿著,可以緩解部分突發(fā)的流量。當(dāng)漏斗未空時(shí),訪問的頻次和令牌放入的頻次變?yōu)橐恢隆?/p>

其他限流器的實(shí)現(xiàn)

uber 開源庫中基于漏斗算法實(shí)現(xiàn)了一個(gè)限流器。漏斗算法可以限制流量的請求速度,并起到削峰填谷的作用。 https://github.com/uber-go/ratelimit

滴滴開源實(shí)現(xiàn)了一個(gè)對http請求的限流器中間件??梢曰谝韵履J较蘖?。

  • 基于IP,路徑,方法,header,授權(quán)用戶等限流
  • 通過自定義方法限流
  • 還支持基于 http header 設(shè)置限流數(shù)據(jù)
  • 實(shí)現(xiàn)方式是基于 github/go/time 實(shí)現(xiàn)的,不同類別的數(shù)據(jù)都存儲(chǔ)在一個(gè)帶超時(shí)時(shí)間的數(shù)據(jù)池中。
  • 代碼地址 https://github.com/didip/tollbooth

golang 網(wǎng)絡(luò)包中還有基于信號量實(shí)現(xiàn)的限流器。 https://github.com/golang/net/blob/master/netutil/listen.go 也值得我們?nèi)W(xué)習(xí)下。

總結(jié)

令牌桶實(shí)現(xiàn)的限流器算法,相較于漏斗算法可以在一定程度上允許突發(fā)的流量進(jìn)入我們的應(yīng)用中,所以在web應(yīng)用中最為廣泛。

在實(shí)際使用時(shí),一般不會(huì)做全局的限流,而是針對某些特征去做精細(xì)化的限流。例如:通過header、x-forward-for 等限制爬蟲的訪問,通過對 ip,session 等用戶信息限制單個(gè)用戶的訪問等。

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

相關(guān)文章

  • go面向?qū)ο蠓绞讲僮鱆SON庫實(shí)現(xiàn)四則運(yùn)算

    go面向?qū)ο蠓绞讲僮鱆SON庫實(shí)現(xiàn)四則運(yùn)算

    這篇文章主要為大家介紹了go面向?qū)ο蠓绞讲僮鱆SON庫實(shí)現(xiàn)四則運(yùn)算的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • Go?語言數(shù)據(jù)結(jié)構(gòu)如何實(shí)現(xiàn)抄一個(gè)list示例詳解

    Go?語言數(shù)據(jù)結(jié)構(gòu)如何實(shí)現(xiàn)抄一個(gè)list示例詳解

    這篇文章主要為大家介紹了Go?語言數(shù)據(jù)結(jié)構(gòu)如何實(shí)現(xiàn)抄一個(gè)list示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • Go語言項(xiàng)目中使用Viper獲取配置信息詳解

    Go語言項(xiàng)目中使用Viper獲取配置信息詳解

    Viper是Go應(yīng)用的完整配置解決方案,它能處理所有類型的配置需求和配置格式,這篇文章主要介紹了Go項(xiàng)目中使用Viper獲取配置信息,需要的可以參考下
    2024-04-04
  • gin 獲取post請求的json body操作

    gin 獲取post請求的json body操作

    這篇文章主要介紹了gin 獲取post請求的json body操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-03-03
  • 一文帶你深入探究Go語言中的sync.Map

    一文帶你深入探究Go語言中的sync.Map

    在?Go?語言中,有一個(gè)非常實(shí)用的并發(fā)安全的?Map?實(shí)現(xiàn):sync.Map,它是在?Go?1.9?版本中引入的。本文我們將深入探討?sync.Map?的基本原理,幫助讀者更好地理解并使用這個(gè)并發(fā)安全的?Map
    2023-04-04
  • Go導(dǎo)入不同目錄下包報(bào)錯(cuò)的解決方法

    Go導(dǎo)入不同目錄下包報(bào)錯(cuò)的解決方法

    包(package)是多個(gè)Go源碼的集合,是一種高級的代碼復(fù)用方案,下面這篇文章主要給大家介紹了關(guān)于Go導(dǎo)入不同目錄下包報(bào)錯(cuò)的解決方法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-06-06
  • gRPC超時(shí)攔截器實(shí)現(xiàn)示例

    gRPC超時(shí)攔截器實(shí)現(xiàn)示例

    這篇文章主要為大家介紹了gRPC超時(shí)攔截器實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Go語言fsnotify接口實(shí)現(xiàn)監(jiān)測文件修改

    Go語言fsnotify接口實(shí)現(xiàn)監(jiān)測文件修改

    這篇文章主要為大家介紹了Go語言fsnotify接口實(shí)現(xiàn)監(jiān)測文件修改的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • 一文徹底理解Golang閉包實(shí)現(xiàn)原理

    一文徹底理解Golang閉包實(shí)現(xiàn)原理

    閉包對于一個(gè)長期寫Java的開發(fā)者來說估計(jì)鮮有耳聞,光這名字感覺就有點(diǎn)"神秘莫測"。這篇文章的主要目的就是從編譯器的角度來分析閉包,徹底搞懂閉包的實(shí)現(xiàn)原理,需要的可以參考一下
    2022-10-10
  • Go語言中的流程控制結(jié)構(gòu)和函數(shù)詳解

    Go語言中的流程控制結(jié)構(gòu)和函數(shù)詳解

    這篇文章主要介紹了Go語言中的流程控制結(jié)構(gòu)和函數(shù)詳解,本文詳細(xì)講解了if、goto、for、switch等控制語句,同時(shí)對函數(shù)相關(guān)知識做了講解,需要的朋友可以參考下
    2014-10-10

最新評論