一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Golang - Golang 限流器的使用和實現示例

Golang 限流器的使用和實現示例

2020-07-26 12:06搬磚程序員帶你飛 Golang

這篇文章主要介紹了Golang 限流器的使用和實現示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

限流器是服務中非常重要的一個組件,在網關設計、微服務、以及普通的后臺應用中都比較常見。它可以限制訪問服務的頻次和速率,防止服務過載,被刷爆。

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

基于令牌桶的限流器實現

在golang 的官方擴展包 time 中(github/go/time),提供了一個基于令牌桶算法的限流器的實現。

原理

令牌桶限流器,有兩個概念:

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

因此,一個令牌桶的限流器,可以限制一個時間間隔內,最多可以承載桶容量的訪問頻次。下面我們看看官方的實現。

實現

限流器的定義

下面是對一個限流器的定義:

?
1
2
3
4
5
6
7
8
9
type Limiter struct {
 limit Limit // 放入桶的頻率  (Limit 為 float64類型)
 burst int  // 桶的大小
 
 mu   sync.Mutex
 tokens float64 // 當前桶內剩余令牌個數
 last time.Time // 最近取走token的時間
 lastEvent time.Time // 最近限流事件的時間
}

其中,核心參數是 limit,burst。 burst 代表了桶的大小,從實際意義上來講,可以理解為服務可以承載的并發量大小;limit 代表了 放入桶的頻率,可以理解為正常情況下,1s內我們的服務可以處理的請求個數。

在令牌發放后,會被保留在Reservation 對象中,定義如下:

?
1
2
3
4
5
6
7
type Reservation struct {
 ok    bool // 是否滿足條件分配到了tokens
 lim    *Limiter // 發送令牌的限流器
 tokens  int  // tokens 的數量
 timeToAct time.Time // 滿足令牌發放的時間
 limit Limit // 令牌發放速度
}

Reservation 對象,描述了一個在達到 timeToAct 時間后,可以獲取到的令牌的數量tokens。 (因為有些需求會做預留的功能,所以timeToAct 并不一定就是當前的時間。

限流器如何限流

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// 在 now 時間需要拿到n個令牌,最多可以等待的時間為maxFutureResrve
// 結果將返回一個預留令牌的對象
func (lim *Limiter) reserveN(now time.Time, n int, maxFutureReserve time.Duration) Reservation {
 lim.mu.Lock()
 
 // 首先判斷是否放入頻次是否為無窮大,如果為無窮大,說明暫時不限流
 if lim.limit == Inf {
  // ...
 }
 
 // 拿到截至now 時間時,可以獲取的令牌tokens數量,上一次拿走令牌的時間last
 now, last, tokens := lim.advance(now)
 
 // 然后更新 tokens 的數量,把需要拿走的去掉
 tokens -= float64(n)
 
 // 如果tokens 為負數,說明需要等待,計算等待的時間
 var waitDuration time.Duration
 if tokens < 0 {
  waitDuration = lim.limit.durationFromTokens(-tokens)
 }
 
 // 計算是否滿足分配條件
 // ① 需要分配的大小不超過桶容量
 // ② 等待時間不超過設定的等待時常
 ok := n <= lim.burst && waitDuration <= maxFutureReserve
 
 // 最后構造一個Reservation對象
 r := Reservation{
  ok:  ok,
  lim:  lim,
  limit: lim.limit,
 }
 if ok {
  r.tokens = n
  r.timeToAct = now.Add(waitDuration)
 }
 
 // 并更新當前limiter 的值
 if ok {
  lim.last = now
  lim.tokens = tokens
  lim.lastEvent = r.timeToAct
 } else {
  lim.last = last
 }
 
 lim.mu.Unlock()
 return r
}

從實現上看,limiter 并不是每隔一段時間更新當前桶中令牌的數量,而是記錄了上次訪問時間和當前桶中令牌的數量。當再次訪問時,通過上次訪問時間計算出當前桶中的令牌的數量,決定是否可以發放令牌。

使用

下面我們通過一個簡單的例子,學習上面介紹的限流器的使用。

?
1
2
3
4
5
6
7
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個令牌,所以當批量訪問該接口時,可以看到如下結果:

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 條記錄
  ...

一開始漏斗滿著,可以緩解部分突發的流量。當漏斗未空時,訪問的頻次和令牌放入的頻次變為一致。

其他限流器的實現

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

滴滴開源實現了一個對http請求的限流器中間件。可以基于以下模式限流。

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

golang 網絡包中還有基于信號量實現的限流器。 https://github.com/golang/net/blob/master/netutil/listen.go 也值得我們去學習下。

總結

令牌桶實現的限流器算法,相較于漏斗算法可以在一定程度上允許突發的流量進入我們的應用中,所以在web應用中最為廣泛。

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

到此這篇關于Golang 限流器的使用和實現示例的文章就介紹到這了,更多相關Golang 限流器內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://segmentfault.com/a/1190000023033365

延伸 · 閱讀

精彩推薦
  • Golanggolang如何使用struct的tag屬性的詳細介紹

    golang如何使用struct的tag屬性的詳細介紹

    這篇文章主要介紹了golang如何使用struct的tag屬性的詳細介紹,從例子說起,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看...

    Go語言中文網11352020-05-21
  • Golanggolang json.Marshal 特殊html字符被轉義的解決方法

    golang json.Marshal 特殊html字符被轉義的解決方法

    今天小編就為大家分享一篇golang json.Marshal 特殊html字符被轉義的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧 ...

    李浩的life12792020-05-27
  • Golanggo日志系統logrus顯示文件和行號的操作

    go日志系統logrus顯示文件和行號的操作

    這篇文章主要介紹了go日志系統logrus顯示文件和行號的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    SmallQinYan12302021-02-02
  • Golanggo語言制作端口掃描器

    go語言制作端口掃描器

    本文給大家分享的是使用go語言編寫的TCP端口掃描器,可以選擇IP范圍,掃描的端口,以及多線程,有需要的小伙伴可以參考下。 ...

    腳本之家3642020-04-25
  • Golanggolang 通過ssh代理連接mysql的操作

    golang 通過ssh代理連接mysql的操作

    這篇文章主要介紹了golang 通過ssh代理連接mysql的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    a165861639710342021-03-08
  • GolangGolang通脈之數據類型詳情

    Golang通脈之數據類型詳情

    這篇文章主要介紹了Golang通脈之數據類型,在編程語言中標識符就是定義的具有某種意義的詞,比如變量名、常量名、函數名等等,Go語言中標識符允許由...

    4272021-11-24
  • GolangGolang中Bit數組的實現方式

    Golang中Bit數組的實現方式

    這篇文章主要介紹了Golang中Bit數組的實現方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧...

    天易獨尊11682021-06-09
  • Golanggolang的httpserver優雅重啟方法詳解

    golang的httpserver優雅重啟方法詳解

    這篇文章主要給大家介紹了關于golang的httpserver優雅重啟的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,...

    helight2992020-05-14
主站蜘蛛池模板: 亚洲色图第四色 | 色婷亚洲| 激情男人天堂 | 国内精品久久久久久不卡影院 | 亚洲第一综合网 | 国产图片综合区 | 狠狠色成人综合 | 国产精品videosse | 亚洲一成人毛片 | 天天干天天色综合网 | 国产成人亚洲精品91专区手机 | 亚洲国产欧美在线成人aaaa | 毛片网站免费观看 | 2019中文字幕| 無码一区中文字幕少妇熟女网站 | 成人私人影院在线观看网址 | 国产精品综合在线 | 国产精品原创巨作无遮挡 | 色哟哟哟在线精品观看视频 | 99热在线免费观看 | 日韩中文字幕在线不卡 | 红色一片在线影视 | 男女一级特黄a大片 | 亚洲视频在线一区二区三区 | 91嫩草国产在线观看免费 | 公交车上插入 | 黄网在线观看免费网站台湾swag | 精品人人做人人爽久久久 | 99久久精品国产免费 | 国产成人啪精品视频站午夜 | 日本色资源 | 好看华人华人经典play | 福利三区 | 国产一卡二卡3卡4卡四卡在线 | 国产一区二区三区四区波多野结衣 | 国产高清dvd | 四虎永久在线精品国产 | 韩国一大片a毛片女同 | 手机能看的黄色网站 | 日韩伦理在线免费观看 | 国产精品久久毛片蜜月 |