<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          「GoCN酷Go推薦」漏桶限流庫 — uber-go/ratelimit

          共 1875字,需瀏覽 4分鐘

           ·

          2021-12-09 12:27

          上次有同學分享了 單機限流器 time/rate 庫,講了 Golang 標準庫中基于令牌桶實現(xiàn)限流組件的 time/rate 使用,同時也講了一些限流算法原理。

          這里分享一個 uber 開源的一套基于漏桶實現(xiàn)的用于服務限流的 golang 庫 ratelimit。

          漏洞算法的理解起來,相較于令牌桶,沒有那么直觀。因為令牌桶是限制 “令牌” 的速率,拿到令牌的請求才能被放行,而漏桶是限制單位時間內(nèi)允許通過的請求數(shù)目,調用方只能嚴格按照預定的間隔順序進行消費調用。

          1

          ratelimit 的基本使用

          官方示例:

          import?(
          ?"fmt"
          ?"time"

          ?"go.uber.org/ratelimit"
          )

          func?main()?{
          ????rl?:=?ratelimit.New(100)?//?per?second

          ????prev?:=?time.Now()
          ????for?i?:=?0;?i?10;?i++?{
          ????????now?:=?rl.Take()
          ????????fmt.Println(i,?now.Sub(prev))
          ????????prev?=?now
          ????}
          }

          在這個例子中,我們給定限流器每秒可以通過 100 個請求,也就是平均每個請求間隔 10ms。因此,最終會每 10ms 打印一行數(shù)據(jù)。輸出結果如下:

          //?Output:
          //?0?0
          //?1?10ms
          //?2?10ms
          //?3?10ms
          //?4?10ms
          //?5?10ms
          //?6?10ms
          //?7?10ms
          //?8?10ms
          //?9?10ms

          2

          高級用法

          最大松弛量

          傳統(tǒng)的漏桶,每個請求的間隔是固定、勻速的,兩次請求 req1 和 req2 之間的延遲至少應該 >=perRequest,然而,在實際上的應用中,流量經(jīng)常是突發(fā)性的。對于突發(fā)這種情況,uber-go 對 Leaky Bucket 做了一些改良,引入了最大松弛量(maxSlack)的概念, 表示允許抵消的最長時間

          漏桶算法的限速邏輯:

          sleepFor?=?t.perRequest?-?now.Sub(t.last)
          if?sleepFor?>?0?{
          ?t.clock.Sleep(sleepFor)
          ?t.last?=?now.Add(sleepFor)
          }?else?{
          ?t.last?=?now
          }

          上面計算 sleepFor 的代碼,不使用最大松弛量的 sleep 邏輯,嚴格要求兩個請求之間必須間隔 t.perRequest 的時間,那么計算 sleepFor 的代碼就是:

          t.sleepFor?=?t.perRequest?-?now.Sub(t.last)

          這樣就會有以下問題:

          我們假設現(xiàn)在有三個請求,req1req2req3,限速區(qū)間為 10msreq1 最先到來,當 req1 完成之后 15msreq2 才到來,依據(jù)限速策略可以對 req2 立即處理,當 req2 完成后,5ms 后, req3 到來,這個時候距離上次請求還不足 10ms,因此還需要等待 5ms 才能繼續(xù)執(zhí)行, 但是,對于這種情況,實際上這三個請求一共消耗了 25ms 才完成,并不是預期的 20ms

          上面這個 case 模擬了一種請求量突發(fā)的狀況。但這里我們可以把之前間隔比較長的請求的時間(累加超出 perRequest 的時延),勻給后面的請求判斷限流時使用。對于上面的 case,因為 req2 相當于多等了 5ms,我們可以把這 5ms 移給 req3 使用。加上 req3 本身就是 5ms 之后過來的,一共剛好 10ms,所以 req3 無需等待,直接可以處理。此時三個請求也恰好一共是 20ms。如下:

          t.sleepFor?+=?t.perRequest?-?now.Sub(t.last)
          if?t.sleepFor?>?0?{
          ??t.clock.Sleep(t.sleepFor)
          ??t.last?=?now.Add(t.sleepFor)
          ??t.sleepFor?=?0
          }?else?{
          ??t.last?=?now
          }

          t.sleepFor > 0,代表此前的請求多余出來的時間,無法完全抵消此次的所需量,因此需要 sleep 相應時間, 同時將 t.sleepFor 置為 0。

          t.sleepFor < 0,說明此次請求間隔大于預期間隔,將多出來的時間累加到 t.sleepFor 即可。

          但是,對于某種情況,請求 1 完成后,請求 2 過了很久到達 ,那么此時對于請求 2 的請求間隔 now.Sub(t.last),會非常大。以至于即使后面大量請求瞬時到達,也無法抵消完這個時間。那這樣就失去了限流的意義。

          為了防止這種情況,ratelimit 就引入了最大松弛量 (maxSlack) 的概念, 該值為負值,表示允許抵消的最長時間,防止以上情況的出現(xiàn)。

          //?當計算出來的?sleepFor?超過一個?maxSlack?時,那么就只?sleep?一個?maxSlack?時間,用于兩次請求時間間隔過大的場景
          if?t.sleepFor??t.sleepFor?=?t.maxSlack
          }

          ratelimit 中 maxSlack 的值為 -10 * time.Second / time.Duration(rate), 是十個請求的間隔大小。我們也可以理解為 ratelimit 允許的最大瞬時請求為 10。

          用法

          ratelimit 的 New 函數(shù),除了可以配置每秒請求數(shù) (QPS), 還提供了一套可選配置項 Option。

          func?New(rate?int,?opts?...Option)?Limiter

          WithoutSlack

          上面說到 ratelimit 中引入了最大松弛量的概念,而且默認的最大松弛量為 10 個請求的間隔時間。

          但是對于需要嚴格的限制請求的固定間隔的時,我們可以利用 WithoutSlack 來取消松弛量的影響。

          limiter?:=?ratelimit.New(100,?ratelimit.WithoutSlack)

          另外,ratelimit 還有其他選項,比如WithClock(clock Clock) 可以用來替換默認時鐘,來實現(xiàn)精度更高或者特殊需求的計時場景。

          3

          Reference

          uber-go 漏桶限流器使用與原理分析 | 編程沉思錄 (cyhone.com)

          開源限流組件分析(一):Uber 的 Leaky Bucket - 熊喵君的博客 | PANDAYCHEN

          限流算法之一 | hzSomthing (hedzr.com)

          uber-go/ratelimit: A Golang blocking leaky-bucket rate limit implementation (github.com)



          《酷Go推薦》招募:


          各位Gopher同學,最近我們社區(qū)打算推出一個類似GoCN每日新聞的新欄目《酷Go推薦》,主要是每周推薦一個庫或者好的項目,然后寫一點這個庫使用方法或者優(yōu)點之類的,這樣可以真正的幫助到大家能夠學習到

          新的庫,并且知道怎么用。


          大概規(guī)則和每日新聞類似,如果報名人多的話每個人一個月輪到一次,歡迎大家報名!戳「閱讀原文」,即可報名


          掃碼也可以加入 GoCN 的大家族喲~




          瀏覽 66
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  伊人色色综合 | 久久色在线视频 | 国产在家激情在线 | 三级网站视频在线观看 | 肏逼网站视频 |