校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃

主頁 > 知識庫 > Go實現各類限流的方法

Go實現各類限流的方法

熱門標簽:壽光微信地圖標注 阿克蘇地圖標注 電話機器人軟件免費 excel地圖標注分布數據 評價高的400電話辦理 涿州代理外呼系統(tǒng) 外呼系統(tǒng)用什么卡 外呼系統(tǒng)顯本地手機號 百度地圖標注后傳給手機

前 言

在開發(fā)高并發(fā)系統(tǒng)時,我們可能會遇到接口訪問頻次過高,為了保證系統(tǒng)的高可用和穩(wěn)定性,這時候就需要做流量限制,你可能是用的 Nginx 這種來控制請求,也可能是用了一些流行的類庫實現。限流是高并發(fā)系統(tǒng)的一大殺器,在設計限流算法之前我們先來了解一下它們是什么。

限 流

限流的目的是通過對并發(fā)訪問請求進行限速,或者對一個時間窗口內的請求進行限速來保護系統(tǒng),一旦達到限制速率則可以拒絕服務、排隊或等待、降級等處理。通過對并發(fā)(或者一定時間窗口內)請求進行限速來保護系統(tǒng),一旦達到限制速率則拒絕服務(定向到錯誤頁或告知資源沒有了)、排隊等待(比如秒殺、評論、下單)、降級(返回兜底數據或默認數據)。

如 圖:

自己魔改出來的漫畫

如圖上的漫畫,在某個時間段流量上來了,服務的接口訪問頻率可能會非???,如果我們沒有對接口訪問頻次做限制可能會導致服務器無法承受過高的壓力掛掉,這時候也可能會產生數據丟失,所以就要對其進行限流處理。

限流算法就可以幫助我們去控制每個接口或程序的函數被調用頻率,它有點兒像保險絲,防止系統(tǒng)因為超過訪問頻率或并發(fā)量而引起癱瘓。我們可能在調用某些第三方的接口的時候會看到類似這樣的響應頭:

X-RateLimit-Limit: 60         //每秒60次請求
X-RateLimit-Remaining: 22     //當前還剩下多少次
X-RateLimit-Reset: 1612184024 //限制重置時間

上面的 HTTP Response 是通過響應頭告訴調用方服務端的限流頻次是怎樣的,保證后端的接口訪問上限。為了解決限流問題出現了很多的算法,它們都有不同的用途,通常的策略就是拒絕超出的請求,或者讓超出的請求排隊等待。

一般來說,限流的常用處理手段有:

  • 計數器
  • 滑動窗口
  • 漏桶
  • 令牌桶

計數器

計數器是一種最簡單限流算法,其原理就是:在一段時間間隔內,對請求進行計數,與閥值進行比較判斷是否需要限流,一旦到了時間臨界點,將計數器清零。這個就像你去坐車一樣,車廂規(guī)定了多少個位置,滿了就不讓上車了,不然就是超載了,被交警叔叔抓到了就要罰款的,如果我們的系統(tǒng)那就不是罰款的事情了,可能直接崩掉了。

  • 可以在程序中設置一個變量 count,當過來一個請求我就將這個數+1,同時記錄請求時間。
  • 當下一個請求來的時候判斷 count 的計數值是否超過設定的頻次,以及當前請求的時間和第一次請求時間是否在 1 分鐘內。
  • 如果在 1 分鐘內并且超過設定的頻次則證明請求過多,后面的請求就拒絕掉。
  • 如果該請求與第一個請求的間隔時間大于計數周期,且 count 值還在限流范圍內,就重置 count。

代碼實現:

package main
 
import (
    "log"
    "sync"
    "time"
)
 
type Counter struct {
    rate  int           //計數周期內最多允許的請求數
    begin time.Time     //計數開始時間
    cycle time.Duration //計數周期
    count int           //計數周期內累計收到的請求數
    lock  sync.Mutex
}
 
func (l *Counter) Allow() bool {
    l.lock.Lock()
    defer l.lock.Unlock()
 
    if l.count == l.rate-1 {
        now := time.Now()
        if now.Sub(l.begin) >= l.cycle {
            //速度允許范圍內, 重置計數器
            l.Reset(now)
            return true
        } else {
            return false
        }
    } else {
        //沒有達到速率限制,計數加1
        l.count++
        return true
    }
}
 
func (l *Counter) Set(r int, cycle time.Duration) {
    l.rate = r
    l.begin = time.Now()
    l.cycle = cycle
    l.count = 0
}
 
func (l *Counter) Reset(t time.Time) {
    l.begin = t
    l.count = 0
}
 
func main() {
    var wg sync.WaitGroup
    var lr Counter
    lr.Set(3, time.Second) // 1s內最多請求3次
    for i := 0; i  10; i++ {
        wg.Add(1)
        log.Println("創(chuàng)建請求:", i)
        go func(i int) {
          if lr.Allow() {
              log.Println("響應請求:", i)
          }
          wg.Done()
        }(i)
 
        time.Sleep(200 * time.Millisecond)
    }
    wg.Wait()
}

OutPut:

2021/02/01 21:16:12 創(chuàng)建請求: 0
2021/02/01 21:16:12 響應請求: 0
2021/02/01 21:16:12 創(chuàng)建請求: 1
2021/02/01 21:16:12 響應請求: 1
2021/02/01 21:16:12 創(chuàng)建請求: 2
2021/02/01 21:16:13 創(chuàng)建請求: 3
2021/02/01 21:16:13 創(chuàng)建請求: 4
2021/02/01 21:16:13 創(chuàng)建請求: 5
2021/02/01 21:16:13 響應請求: 5
2021/02/01 21:16:13 創(chuàng)建請求: 6
2021/02/01 21:16:13 響應請求: 6
2021/02/01 21:16:13 創(chuàng)建請求: 7
2021/02/01 21:16:13 響應請求: 7
2021/02/01 21:16:14 創(chuàng)建請求: 8
2021/02/01 21:16:14 創(chuàng)建請求: 9

可以看到我們設置的是每200ms創(chuàng)建一個請求,明顯高于1秒最多3個請求的限制,運行起來之后發(fā)現編號為 2、3、4、8、9 的請求被丟棄,說明限流成功。

那么問題來了,如果有個需求對于某個接口 /query 每分鐘最多允許訪問 200 次,假設有個用戶在第 59 秒的最后幾毫秒瞬間發(fā)送 200 個請求,當 59 秒結束后 Counter 清零了,他在下一秒的時候又發(fā)送 200 個請求。那么在 1 秒鐘內這個用戶發(fā)送了 2 倍的請求,這個是符合我們的設計邏輯的,這也是計數器方法的設計缺陷,系統(tǒng)可能會承受惡意用戶的大量請求,甚至擊穿系統(tǒng)。

如下圖:

這種方法雖然簡單,但也有個大問題就是沒有很好的處理單位時間的邊界。

滑動窗口

滑動窗口是針對計數器存在的臨界點缺陷,所謂 滑動窗口(Sliding window) 是一種流量控制技術,這個詞出現在 TCP 協議中。滑動窗口把固定時間片進行劃分,并且隨著時間的流逝,進行移動,固定數量的可以移動的格子,進行計數并判斷閥值。

如 圖:

上圖中我們用紅色的虛線代表一個時間窗口(一分鐘),每個時間窗口有 6 個格子,每個格子是 10 秒鐘。每過 10 秒鐘時間窗口向右移動一格,可以看紅色箭頭的方向。我們?yōu)槊總€格子都設置一個獨立的計數器 Counter,假如一個請求在 0:45 訪問了那么我們將第五個格子的計數器 +1(也是就是 0:40~0:50),在判斷限流的時候需要把所有格子的計數加起來和設定的頻次進行比較即可。

那么滑動窗口如何解決我們上面遇到的問題呢?來看下面的圖:

當用戶在0:59 秒鐘發(fā)送了 200個請求就會被第六個格子的計數器記錄 +200,當下一秒的時候時間窗口向右移動了一個,此時計數器已經記錄了該用戶發(fā)送的 200 個請求,所以再發(fā)送的話就會觸發(fā)限流,則拒絕新的請求。

其實計數器就是滑動窗口啊,只不過只有一個格子而已,所以想讓限流做的更精確只需要劃分更多的格子就可以了,為了更精確我們也不知道到底該設置多少個格子,格子的數量影響著滑動窗口算法的精度,依然有時間片的概念,無法根本解決臨界點問題

相關算法實現 github.com/RussellLuo/slidingwindow

漏 桶

漏桶算法(Leaky Bucket),原理就是一個固定容量的漏桶,按照固定速率流出水滴。用過水龍頭都知道,打開龍頭開關水就會流下滴到水桶里,而漏桶指的是水桶下面有個漏洞可以出水。如果水龍頭開的特別大那么水流速就會過大,這樣就可能導致水桶的水滿了然后溢出。

如 圖:

一個固定容量的桶,有水流進來,也有水流出去。對于流進來的水來說,我們無法預計一共有多少水會流進來,也無法預計水流的速度。但是對于流出去的水來說,這個桶可以固定水流出的速率(處理速度),從而達到 流量整形 和 流量控制 的效果。

代碼實現:

type LeakyBucket struct {
    rate       float64 //固定每秒出水速率
    capacity   float64 //桶的容量
    water      float64 //桶中當前水量
    lastLeakMs int64   //桶上次漏水時間戳 ms

    lock sync.Mutex
}

func (l *LeakyBucket) Allow() bool {
    l.lock.Lock()
    defer l.lock.Unlock()

    now := time.Now().UnixNano() / 1e6
    eclipse := float64((now - l.lastLeakMs)) * l.rate / 1000 //先執(zhí)行漏水
    l.water = l.water - eclipse                              //計算剩余水量
    l.water = math.Max(0, l.water)                           //桶干了
    l.lastLeakMs = now
    if (l.water + 1)  l.capacity {
        // 嘗試加水,并且水還未滿
        l.water++
        return true
    } else {
        // 水滿,拒絕加水
        return false
    }
}

func (l *LeakyBucket) Set(r, c float64) {
    l.rate = r
    l.capacity = c
    l.water = 0
    l.lastLeakMs = time.Now().UnixNano() / 1e6
}

漏桶算法有以下特點:

  • 漏桶具有固定容量,出水速率是固定常量(流出請求)
  • 如果桶是空的,則不需流出水滴
  • 可以以任意速率流入水滴到漏桶(流入請求)
  • 如果流入水滴超出了桶的容量,則流入的水滴溢出(新請求被拒絕)

漏桶限制的是常量流出速率(即流出速率是一個固定常量值),所以最大的速率就是出水的速率,不能出現突發(fā)流量。

令牌桶算法

令牌桶算法(Token Bucket)是網絡流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常使用的一種算法。典型情況下,令牌桶算法用來控制發(fā)送到網絡上的數據的數目,并允許突發(fā)數據的發(fā)送。

我們有一個固定的桶,桶里存放著令牌(token)。一開始桶是空的,系統(tǒng)按固定的時間(rate)往桶里添加令牌,直到桶里的令牌數滿,多余的請求會被丟棄。當請求來的時候,從桶里移除一個令牌,如果桶是空的則拒絕請求或者阻塞。

實現代碼:

type TokenBucket struct {
    rate         int64 //固定的token放入速率, r/s
    capacity     int64 //桶的容量
    tokens       int64 //桶中當前token數量
    lastTokenSec int64 //桶上次放token的時間戳 s

    lock sync.Mutex
}

func (l *TokenBucket) Allow() bool {
    l.lock.Lock()
    defer l.lock.Unlock()

    now := time.Now().Unix()
    l.tokens = l.tokens + (now-l.lastTokenSec)*l.rate // 先添加令牌
    if l.tokens > l.capacity {
        l.tokens = l.capacity
    }
    l.lastTokenSec = now
    if l.tokens > 0 {
        // 還有令牌,領取令牌
        l.tokens--
        return true
    } else {
        // 沒有令牌,則拒絕
        return false
    }
}

func (l *TokenBucket) Set(r, c int64) {
    l.rate = r
    l.capacity = c
    l.tokens = 0
    l.lastTokenSec = time.Now().Unix()
}

令牌桶有以下特點:

  • 令牌按固定的速率被放入令牌桶中
  • 桶中最多存放 B 個令牌,當桶滿時,新添加的令牌被丟棄或拒絕
  • 如果桶中的令牌不足 N 個,則不會刪除令牌,且請求將被限流(丟棄或阻塞等待)

令牌桶限制的是平均流入速率(允許突發(fā)請求,只要有令牌就可以處理,支持一次拿3個令牌,4個令牌...),并允許一定程度突發(fā)流量。

小 結

目前常用的是令牌桶這種,本文介紹了幾種常見的限流算法實現

到此這篇關于Go實現各類限流的文章就介紹到這了,更多相關Go實現各類限流內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • Golang模擬令牌桶進行對訪問的限流方式
  • 詳解Golang實現請求限流的幾種辦法
  • golang接口IP限流,IP黑名單,IP白名單的實例
  • Golang 限流器的使用和實現示例
  • Golang實現請求限流的幾種辦法(小結)

標簽:雞西 吐魯番 銅川 梅河口 蘭州 欽州 汕頭 重慶

巨人網絡通訊聲明:本文標題《Go實現各類限流的方法》,本文關鍵詞  實現,各類,限,流的,方法,;如發(fā)現本文內容存在版權問題,煩請?zhí)峁┫嚓P信息告之我們,我們將及時溝通與處理。本站內容系統(tǒng)采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《Go實現各類限流的方法》相關的同類信息!
  • 本頁收集關于Go實現各類限流的方法的相關信息資訊供網民參考!
  • 推薦文章
    校园春色亚洲色图_亚洲视频分类_中文字幕精品一区二区精品_麻豆一区区三区四区产品精品蜜桃
    久久精品国产久精国产爱| 欧美日韩国产首页在线观看| 欧洲在线/亚洲| 久久久精品tv| 日本怡春院一区二区| 成人动漫视频在线| 精品久久国产老人久久综合| 亚洲综合一区在线| 成人av影视在线观看| 精品免费日韩av| 日韩中文欧美在线| 欧美视频三区在线播放| 亚洲色图20p| 国产91丝袜在线播放| 日韩一级片在线观看| 亚洲在线免费播放| 色综合天天天天做夜夜夜夜做| 精品国产一区二区三区av性色| 午夜影院久久久| 在线视频一区二区三区| 亚洲欧美另类久久久精品 | 26uuu色噜噜精品一区二区| 亚洲国产中文字幕| 欧美午夜精品久久久| 日韩美女精品在线| 91网站视频在线观看| 国产精品乱人伦中文| 91亚洲精华国产精华精华液| 久久精品亚洲精品国产欧美 | 亚洲精品v日韩精品| av在线不卡免费看| 中文字幕一区在线观看视频| 成人黄色大片在线观看| 中文字幕在线观看一区| 成人午夜精品一区二区三区| 中日韩av电影| 99re亚洲国产精品| 亚洲专区一二三| 欧美高清hd18日本| 久久aⅴ国产欧美74aaa| 精品噜噜噜噜久久久久久久久试看 | 亚洲精品在线三区| 国产激情偷乱视频一区二区三区| 久久在线观看免费| 国产成人在线免费观看| 国产精品亲子乱子伦xxxx裸| 不卡影院免费观看| 一级特黄大欧美久久久| 91麻豆福利精品推荐| 亚洲一区二区精品视频| 欧美日产国产精品| 国产一区亚洲一区| 国产精品久久久久久久久久久免费看 | 欧美日本一区二区| 麻豆91小视频| 国产人妖乱国产精品人妖| 成人av午夜影院| 午夜久久久久久久久 | 91福利在线看| 男女性色大片免费观看一区二区| 久久夜色精品一区| 91啪在线观看| 免费视频一区二区| 国产精品久久免费看| 欧美综合一区二区三区| 麻豆久久久久久久| 国产精品狼人久久影院观看方式| 日韩免费视频一区| 色婷婷综合视频在线观看| 日本女人一区二区三区| 国产亚洲综合色| 在线观看日韩电影| 国产一区二区在线电影| 一区二区三区在线免费视频| 欧美成人精品福利| 在线精品视频免费观看| 国产乱淫av一区二区三区| 亚洲国产一区二区在线播放| 2023国产一二三区日本精品2022| av不卡免费在线观看| 麻豆国产欧美一区二区三区| 亚洲免费在线观看| 国产欧美日韩三区| 91精品婷婷国产综合久久性色 | 欧美体内she精视频| 国内精品免费在线观看| 亚洲国产美女搞黄色| 久久亚洲精华国产精华液| 欧美优质美女网站| 国产精品一区三区| 蜜臀精品久久久久久蜜臀| 亚洲人123区| 国产视频一区在线观看| 欧美一区二区视频在线观看2022| www.亚洲在线| 国产最新精品精品你懂的| 视频一区国产视频| 一级精品视频在线观看宜春院| 国产亚洲人成网站| 日韩一级黄色片| 在线观看日韩电影| 91丨porny丨中文| 成人蜜臀av电影| 国产河南妇女毛片精品久久久| 视频一区视频二区中文| 一区二区三区四区乱视频| 国产精品久久二区二区| 久久久久久久久久久久久女国产乱| 欧美视频一区二| 欧美在线视频不卡| 欧美性三三影院| 欧美探花视频资源| 欧美图片一区二区三区| 欧美午夜精品电影| 欧美老人xxxx18| 欧美色图激情小说| 欧美精品丝袜中出| 欧美日韩国产一区二区三区地区| 一本色道**综合亚洲精品蜜桃冫| 不卡欧美aaaaa| 色综合色综合色综合色综合色综合| 99re视频精品| 在线视频欧美区| 精品久久久久av影院| 日韩欧美不卡一区| 欧美zozo另类异族| 国产女主播视频一区二区| 欧美激情中文字幕一区二区| 国产午夜精品在线观看| 中文乱码免费一区二区| 亚洲三级电影网站| 亚洲成av人片在线| 看片的网站亚洲| 国产精品88888| 成人在线综合网站| 日本韩国一区二区三区视频| 欧美性猛片xxxx免费看久爱| 91精品国产综合久久久久久久久久 | 国产在线一区二区综合免费视频| 国产一区二区精品在线观看| av电影在线观看完整版一区二区| 色哟哟国产精品| 欧美一卡2卡3卡4卡| 久久婷婷国产综合精品青草| 国产精品免费人成网站| 亚洲午夜精品在线| 精品一区二区三区久久久| 不卡电影免费在线播放一区| 欧美日韩精品一区二区三区四区 | 日本高清免费不卡视频| 91麻豆精品国产91| 欧美激情在线看| 亚洲国产另类av| 麻豆国产精品777777在线| 不卡高清视频专区| 日韩欧美国产成人一区二区| 国产精品国产三级国产专播品爱网| 亚洲国产成人高清精品| 狠狠色伊人亚洲综合成人| 色播五月激情综合网| 欧美成人乱码一区二区三区| 国产精品麻豆网站| 久久99精品久久久| 91美女蜜桃在线| 久久免费偷拍视频| 午夜精品视频一区| 99re热视频精品| 久久新电视剧免费观看| 午夜久久久影院| 91年精品国产| 国产亚洲欧洲997久久综合| 亚洲成在人线免费| 日韩午夜激情av| 国产调教视频一区| 日韩福利电影在线| 欧美性一二三区| 中文字幕在线观看不卡视频| 国产一本一道久久香蕉| 欧美精品在线观看一区二区| 国产精品国产自产拍高清av| 精品午夜久久福利影院| 欧美区一区二区三区| 一区二区三区在线免费视频| 粉嫩一区二区三区性色av| 日韩欧美国产系列| 青青草伊人久久| 91精品麻豆日日躁夜夜躁| 一区二区三区色| 99精品久久99久久久久| 国产清纯在线一区二区www| 国产一区二区三区久久久| 日韩一区二区免费视频| 亚洲高清免费视频| 欧美在线|欧美| 一二三四区精品视频| 一本到三区不卡视频| 亚洲视频一区在线观看| 波多野结衣精品在线| 国产精品色婷婷| 成人免费不卡视频|