精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Go-Zero 是如何實(shí)現(xiàn)令牌桶限流的?

開發(fā) 前端
生成的令牌放入令牌桶中存放,如果令牌桶滿了則多余的令牌會直接丟棄,當(dāng)請求到達(dá)時(shí),會嘗試從令牌桶中取令牌,取到了令牌的請求可以執(zhí)行; 如果桶空了,那么嘗試取令牌的請求會被直接丟棄。

上一篇文章介紹了 如何實(shí)現(xiàn)計(jì)數(shù)器限流。主要有兩種實(shí)現(xiàn)方式,分別是固定窗口和滑動窗口,并且分析了 go-zero 采用固定窗口方式實(shí)現(xiàn)的源碼。

但是采用固定窗口實(shí)現(xiàn)的限流器會有兩個(gè)問題:

  1. 會出現(xiàn)請求量超出限制值兩倍的情況
  2. 無法很好處理流量突增問題

這篇文章來介紹一下令牌桶算法,可以很好解決以上兩個(gè)問題。

工作原理

算法概念如下:

  • 令牌以固定速率生成;
  • 生成的令牌放入令牌桶中存放,如果令牌桶滿了則多余的令牌會直接丟棄,當(dāng)請求到達(dá)時(shí),會嘗試從令牌桶中取令牌,取到了令牌的請求可以執(zhí)行;
  • 如果桶空了,那么嘗試取令牌的請求會被直接丟棄。

圖片圖片

令牌桶算法既能夠?qū)⑺械恼埱笃骄植嫉綍r(shí)間區(qū)間內(nèi),又能接受服務(wù)器能夠承受范圍內(nèi)的突發(fā)請求,因此是目前使用較為廣泛的一種限流算法。

源碼實(shí)現(xiàn)

源碼分析我們還是以 go-zero 項(xiàng)目為例,首先來看生成令牌的部分,依然是使用 Redis 來實(shí)現(xiàn)。

// core/limit/tokenlimit.go

// 生成 token 速率
script = `local rate = tonumber(ARGV[1])
// 通容量
local capacity = tonumber(ARGV[2])
// 當(dāng)前時(shí)間戳
local now = tonumber(ARGV[3])
// 請求數(shù)量
local requested = tonumber(ARGV[4])
// 需要多少秒才能把桶填滿
local fill_time = capacity/rate
// 向下取整,ttl 為填滿時(shí)間 2 倍
local ttl = math.floor(fill_time*2)
// 當(dāng)前桶剩余容量,如果為 nil,說明第一次使用,賦值為桶最大容量
local last_tokens = tonumber(redis.call("get", KEYS[1]))
if last_tokens == nil then
    last_tokens = capacity
end

// 上次請求時(shí)間戳,如果為 nil 則賦值 0
local last_refreshed = tonumber(redis.call("get", KEYS[2]))
if last_refreshed == nil then
    last_refreshed = 0
end

// 距離上一次請求的時(shí)間跨度
local delta = math.max(0, now-last_refreshed)
// 距離上一次請求的時(shí)間跨度能生成的 token 數(shù)量和桶內(nèi)剩余 token 數(shù)量的和
// 與桶容量比較,取二者的小值
local filled_tokens = math.min(capacity, last_tokens+(delta*rate))
// 判斷請求數(shù)量和桶內(nèi) token 數(shù)量的大小
local allowed = filled_tokens >= requested
// 被請求消耗掉之后,更新剩余 token 數(shù)量
local new_tokens = filled_tokens
if allowed then
    new_tokens = filled_tokens - requested
end

// 更新 redis token
redis.call("setex", KEYS[1], ttl, new_tokens)
// 更新 redis 刷新時(shí)間
redis.call("setex", KEYS[2], ttl, now)

return allowed`

Redis 中主要保存兩個(gè) key,分別是 token 數(shù)量和刷新時(shí)間。

核心思想就是比較兩次請求時(shí)間間隔內(nèi)生成的 token 數(shù)量 + 桶內(nèi)剩余 token 數(shù)量,和請求量之間的大小,如果滿足則允許,否則則不允許。

限流器初始化:

// A TokenLimiter controls how frequently events are allowed to happen with in one second.
type TokenLimiter struct {
    // 生成 token 速率
    rate           int
    // 桶容量
    burst          int
    store          *redis.Redis
    // 桶 key
    tokenKey       string
    // 桶刷新時(shí)間 key
    timestampKey   string
    rescueLock     sync.Mutex
    // redis 健康標(biāo)識
    redisAlive     uint32
    // redis 健康監(jiān)控啟動狀態(tài)
    monitorStarted bool
    // 內(nèi)置單機(jī)限流器
    rescueLimiter  *xrate.Limiter
}

// NewTokenLimiter returns a new TokenLimiter that allows events up to rate and permits
// bursts of at most burst tokens.
func NewTokenLimiter(rate, burst int, store *redis.Redis, key string) *TokenLimiter {
    tokenKey := fmt.Sprintf(tokenFormat, key)
    timestampKey := fmt.Sprintf(timestampFormat, key)

    return &TokenLimiter{
        rate:          rate,
        burst:         burst,
        store:         store,
        tokenKey:      tokenKey,
        timestampKey:  timestampKey,
        redisAlive:    1,
        rescueLimiter: xrate.NewLimiter(xrate.Every(time.Second/time.Duration(rate)), burst),
    }
}

其中有一個(gè)變量 rescueLimiter,這是一個(gè)進(jìn)程內(nèi)的限流器。如果 Redis 發(fā)生故障了,那么就使用這個(gè),算是一個(gè)保障,盡量避免系統(tǒng)被突發(fā)流量拖垮。

圖片圖片

提供了四個(gè)可調(diào)用方法:

// Allow is shorthand for AllowN(time.Now(), 1).
func (lim *TokenLimiter) Allow() bool {
    return lim.AllowN(time.Now(), 1)
}

// AllowCtx is shorthand for AllowNCtx(ctx,time.Now(), 1) with incoming context.
func (lim *TokenLimiter) AllowCtx(ctx context.Context) bool {
    return lim.AllowNCtx(ctx, time.Now(), 1)
}

// AllowN reports whether n events may happen at time now.
// Use this method if you intend to drop / skip events that exceed the rate.
// Otherwise, use Reserve or Wait.
func (lim *TokenLimiter) AllowN(now time.Time, n int) bool {
    return lim.reserveN(context.Background(), now, n)
}

// AllowNCtx reports whether n events may happen at time now with incoming context.
// Use this method if you intend to drop / skip events that exceed the rate.
// Otherwise, use Reserve or Wait.
func (lim *TokenLimiter) AllowNCtx(ctx context.Context, now time.Time, n int) bool {
    return lim.reserveN(ctx, now, n)
}

最終調(diào)用的都是 reverveN 方法:

func (lim *TokenLimiter) reserveN(ctx context.Context, now time.Time, n int) bool {
    // 判斷 Redis 健康狀態(tài),如果 Redis 故障,則使用進(jìn)程內(nèi)限流器
    if atomic.LoadUint32(&lim.redisAlive) == 0 {
        return lim.rescueLimiter.AllowN(now, n)
    }

    // 執(zhí)行限流腳本
    resp, err := lim.store.EvalCtx(ctx,
        script,
        []string{
            lim.tokenKey,
            lim.timestampKey,
        },
        []string{
            strconv.Itoa(lim.rate),
            strconv.Itoa(lim.burst),
            strconv.FormatInt(now.Unix(), 10),
            strconv.Itoa(n),
        })
    // redis allowed == false
    // Lua boolean false -> r Nil bulk reply
    if err == redis.Nil {
        return false
    }
    if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) {
        logx.Errorf("fail to use rate limiter: %s", err)
        return false
    }
    if err != nil {
        logx.Errorf("fail to use rate limiter: %s, use in-process limiter for rescue", err)
        // 如果有異常的話,會啟動進(jìn)程內(nèi)限流
        lim.startMonitor()
        return lim.rescueLimiter.AllowN(now, n)
    }

    code, ok := resp.(int64)
    if !ok {
        logx.Errorf("fail to eval redis script: %v, use in-process limiter for rescue", resp)
        lim.startMonitor()
        return lim.rescueLimiter.AllowN(now, n)
    }

    // redis allowed == true
    // Lua boolean true -> r integer reply with value of 1
    return code == 1
}

最后看一下進(jìn)程內(nèi)限流的啟動與恢復(fù):

func (lim *TokenLimiter) startMonitor() {
    lim.rescueLock.Lock()
    defer lim.rescueLock.Unlock()

    // 需要加鎖保護(hù),如果程序已經(jīng)啟動了,直接返回,不要重復(fù)啟動
    if lim.monitorStarted {
        return
    }

    lim.monitorStarted = true
    atomic.StoreUint32(&lim.redisAlive, 0)

    go lim.waitForRedis()
}

func (lim *TokenLimiter) waitForRedis() {
    ticker := time.NewTicker(pingInterval)
    // 更新監(jiān)控進(jìn)程的狀態(tài)
    defer func() {
        ticker.Stop()
        lim.rescueLock.Lock()
        lim.monitorStarted = false
        lim.rescueLock.Unlock()
    }()

    for range ticker.C {
        // 對 redis 進(jìn)行健康監(jiān)測,如果 redis 服務(wù)恢復(fù)了
        // 則更新 redisAlive 標(biāo)識,并退出 goroutine
        if lim.store.Ping() {
            atomic.StoreUint32(&lim.redisAlive, 1)
            return
        }
    }
}

參考文章:

責(zé)任編輯:武曉燕 來源: AlwaysBeta
相關(guān)推薦

2023-08-07 08:01:15

2022-01-12 12:46:32

Go限流保障

2023-08-28 08:00:45

2020-10-16 09:34:39

漏桶令牌桶限流

2025-05-26 04:00:00

2024-04-28 14:46:55

gozero微服務(wù)技巧

2024-11-05 15:02:41

2025-05-23 10:10:00

限流算法系統(tǒng)Go

2021-05-31 07:01:46

限流算法令牌

2024-12-25 15:44:15

2024-02-04 10:08:34

2025-04-08 09:20:00

Sentinel限流微服務(wù)

2023-02-20 08:08:48

限流算法計(jì)數(shù)器算法令牌桶算法

2025-01-21 08:31:12

2022-05-19 14:14:26

go語言限流算法

2023-10-16 16:00:27

Redis限流

2025-08-27 02:15:00

2025-07-01 02:00:00

Spring接口限流高并發(fā)

2023-11-20 10:09:59

2021-03-30 10:46:42

SpringBoot計(jì)數(shù)器漏桶算法
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

久久欧美在线电影| 欧美一区二区三区免费大片| 欧美中文娱乐网| 中文av免费观看| 亚洲精品午夜av福利久久蜜桃| 欧美一区二区三区免费大片| 成人在线免费观看av| 欧美精品电影| 成人三级在线视频| 国产精品一区二区3区| 久久婷婷综合国产| 欧美午夜精彩| 亚洲第一精品自拍| 成人综合久久网| 青青青免费在线视频| ...xxx性欧美| 欧美激情www| 亚洲国产视频一区二区三区| 久久久久久自在自线| 欧美国产第一页| 成熟人妻av无码专区| 中文字幕视频精品一区二区三区| 色综合天天做天天爱| 欧美人与动牲交xxxxbbbb| 第一页在线观看| av在线播放一区二区三区| 成人黄色免费在线观看| 69xxxx国产| 亚洲欧洲日本mm| 久久中文字幕在线视频| 中文字幕伦理片| 欧美三级自拍| 欧美成人一区二区三区在线观看| 天堂一区在线观看| 日韩精品一区二区三区| 亚洲成精国产精品女| 吴梦梦av在线| 日本中文字幕视频在线| 国产欧美一区二区精品性| 国偷自产av一区二区三区小尤奈| www.国产欧美| 国产酒店精品激情| 成人情趣片在线观看免费| 久久精品偷拍视频| 玖玖国产精品视频| 青青青国产精品一区二区| 亚洲免费激情视频| 国一区二区在线观看| 久久成人这里只有精品| 国产麻豆视频在线观看| 久久久久久久久久久妇女| 在线看日韩欧美| 欧美偷拍一区二区三区| 精品九九在线| 亚洲亚裔videos黑人hd| 色欲av无码一区二区三区| 欧美日韩看看2015永久免费| 日韩电影免费观看中文字幕 | www.久久久.com| 欧美日韩一级视频| 污污网站免费观看| 亚洲老司机网| 欧美一区二区三区在线视频| 国产探花在线观看视频| 亚洲网址在线观看| 亚洲精品一区二区三区蜜桃下载| www.555国产精品免费| 久久精品福利| 亚洲美腿欧美激情另类| 国产毛片欧美毛片久久久| 日韩中文在线电影| 久久精品99无色码中文字幕| 国产一区二区精彩视频| 亚洲国内精品| 欧美一级片久久久久久久| 日韩污视频在线观看| 乱码第一页成人| 国产精品高清网站| 一区二区三区免费在线| 国产成人综合精品三级| 国产一区二区三区四区五区加勒比| 色资源在线观看| 国产欧美日韩三区| 欧美少妇在线观看| 欧美裸体视频| 欧美日韩午夜精品| 久久久久亚洲av无码专区首jn| 都市激情亚洲| 一区二区三欧美| 国产1区2区3区4区| 国产精品亚洲综合久久| 国产精品人人做人人爽| 国产夫妻自拍av| av网站免费线看精品| 日韩免费av电影| 最爽无遮挡行房视频在线| 黑人巨大精品欧美一区二区三区| 热久久精品免费视频| 99久久香蕉| 中文字幕亚洲欧美日韩2019| 日本特黄一级片| 毛片av一区二区| 国产精品嫩草在线观看| 91se在线| 偷窥国产亚洲免费视频| 国内av免费观看| 国产欧美高清视频在线| 欧美精品www在线观看| 波多野结衣视频免费观看| 丰满亚洲少妇av| 亚洲成人一区二区三区| 岛国在线视频网站| 3d动漫精品啪啪| 舐め犯し波多野结衣在线观看| 欧美三级午夜理伦三级中文幕| 国产97在线|亚洲| 丰满少妇在线观看bd| 国产精品你懂的| 国产男女在线观看| 欧美激情三级| 少妇高潮久久久久久潘金莲| 黑人一级大毛片| 国产黄色精品网站| 亚洲精品国产一区| 毛片无码国产| 亚洲激情第一页| 欧美激情国产精品免费| 精品亚洲免费视频| 亚洲精品电影在线一区| 综合日韩av| 亚洲国产三级网| 欧美极品视频在线观看| 狠狠久久亚洲欧美| 午夜精品一区二区在线观看的| 中文不卡1区2区3区| 亚洲精品在线免费观看视频| 极品久久久久久| 国产综合久久久久久鬼色| 亚洲国产精品一区在线观看不卡| 欧美极品免费| 亚洲天堂av在线播放| 五月婷婷色丁香| www激情久久| 播放灌醉水嫩大学生国内精品| 国产精品sss在线观看av| 欧美日韩福利视频| 亚洲欧美高清视频| 亚洲国产日韩精品| 国产精品91av| 一区二区福利| 你懂的视频在线一区二区| 欧美13videosex性极品| 亚洲精品中文字| 一级黄色在线视频| 国产三级久久久| 国产主播中文字幕| 成人久久久久| 成人网中文字幕| 动漫一区在线| 精品福利av导航| 久久久久久久久97| 波多野结衣视频一区| 日韩小视频在线播放| 亚洲女娇小黑人粗硬| 国产成人精品电影久久久| 懂色一区二区三区| 欧美福利电影网| 九九九在线视频| 337p粉嫩大胆色噜噜噜噜亚洲| 北条麻妃在线视频| 亚洲va在线| 99se婷婷在线视频观看| 精精国产xxxx视频在线野外| 亚洲视频综合网| 国产女18毛片多18精品| 亚洲综合免费观看高清完整版 | 久久av在线看| 乱色精品无码一区二区国产盗| 欧美丝袜一区二区| 秋霞网一区二区三区| 国产精品一区二区在线看| 精品无码一区二区三区爱欲| 国产精品一区高清| 亚洲一区二区中文| 国产无遮挡裸体视频在线观看| 亚洲视频自拍偷拍| 亚洲AV无码一区二区三区性| 91久久精品一区二区二区| 999久久久国产| 99九九99九九九视频精品| 男女污污的视频| 亚洲婷婷在线| 视频一区视频二区视频| 96sao在线精品免费视频| 国产精品高精视频免费| 欧美家庭影院| 中文日韩在线观看| 网站黄在线观看| 这里只有精品99re| 好看的av在线| 一二三四区精品视频| 老熟妇一区二区| 成人av网站大全| 国内自拍第二页| 老司机精品久久| 国产av人人夜夜澡人人爽麻豆| av在线不卡免费观看| 好吊妞www.84com只有这里才有精品 | 国产精品99久久久久久人| av免费网站在线| 国产午夜精品视频| 少妇一区二区三区四区| 69av一区二区三区| 波多野结衣爱爱| 婷婷成人综合网| 一区二区视频免费看| 国产丝袜美腿一区二区三区| 日本少妇xxxx| 国产成人精品一区二| 91精品无人成人www| 亚洲综合电影一区二区三区| 欧美黑人在线观看| 香蕉久久网站| 亚洲区一区二区三区| 亚洲人成精品久久久| 国产日韩一区欧美| 亚洲国产精品免费视频| 国产免费久久av| 日韩天堂在线| 国产精品xxx视频| 黑人巨大亚洲一区二区久 | 欧美特级黄色片| 日韩欧美亚洲综合| 日韩三级视频在线播放| 亚洲国产精品人人做人人爽| 免费三片在线播放| 亚洲另类中文字| 国产探花在线免费观看| 亚洲精品视频观看| 欧美精品久久久久久久久46p| 国产精品久久久久国产精品日日| 四虎国产成人精品免费一女五男| 久久久亚洲国产美女国产盗摄| 黄色性生活一级片| 91美女福利视频| 亚洲精品成人无码| 国产欧美一区二区三区在线老狼| 成人免费无遮挡无码黄漫视频| 久久伊人蜜桃av一区二区| 成年人网站免费看| 久久色成人在线| www.99热| 国产精品成人免费| 成年人一级黄色片| 亚洲国产成人porn| 久久亚洲天堂网| 在线观看视频一区二区欧美日韩| 91视频在线视频| 欧美精品视频www在线观看| 影音先锋国产在线| 6080午夜不卡| 熟妇人妻系列aⅴ无码专区友真希| 亚洲国产第一页| 经典三级在线| 久久久99久久精品女同性| 色yeye免费人成网站在线观看| 欧美精品xxx| 美女18一级毛片一品久道久久综合| 国产精品精品久久久| 3d动漫一区二区三区在线观看| 99国产在线观看| 色橹橹欧美在线观看视频高清 | 成人在线免费视频| 色老头一区二区三区在线观看| 黄在线免费观看| 国内精久久久久久久久久人| 欧洲av一区二区| 亚洲va码欧洲m码| 美女午夜精品| 亚洲精品美女久久7777777| 欧美黄在线观看| 日本成人在线免费视频| 国产一区二三区| 国产精品1000部啪视频| 亚洲欧洲综合另类| 精品欧美一区二区三区免费观看| 欧美日韩国产高清一区二区三区 | 中文字幕亚洲乱码熟女1区2区| 欧美视频第二页| 欧美一区二区公司| 综合激情国产一区| 999福利在线视频| 国产日本欧美视频| 西野翔中文久久精品国产| 一区二区三区四区不卡| 国产欧美日韩一区二区三区在线| 在线看的黄色网址| 不卡一区二区在线| 久久人妻无码aⅴ毛片a片app| 性欧美疯狂xxxxbbbb| 一本色道久久综合无码人妻| 亚洲精品videossex少妇| 免费观看在线黄色网| 欧美综合在线观看| 成人av动漫| 精品国产一区二区三区在线| 青草国产精品久久久久久| 国产香蕉精品视频| 国产精品国产三级国产aⅴ中文 | 日韩一区二区电影| 超碰免费在线| 青草热久免费精品视频| 风间由美性色一区二区三区四区| 最新精品视频| 日本欧美一区二区| 免费a级黄色片| 亚洲第一成人在线| 国产丰满果冻videossex| 综合网中文字幕| 欧亚一区二区| 欧美精品欧美精品| 亚洲看片免费| 久久久久亚洲av无码网站| 亚洲蜜臀av乱码久久精品蜜桃| 亚洲天堂男人av| 亚洲精品av在线| 91九色美女在线视频| av成人观看| 自产国语精品视频| 精品国产鲁一鲁一区二区三区| 国产精品乱码一区二区三区软件| www五月天com| 亚洲人成电影网站色www| 国产伦精品一区二区三区视频金莲| 国产区欧美区日韩区| 中文精品视频| 手机在线看片日韩| 婷婷中文字幕综合| 亚洲色图21p| 日本亚洲欧美成人| 国产成人精品999在线观看| 凹凸国产熟女精品视频| 久久久久九九视频| 潘金莲一级淫片aaaaaa播放| 亚洲午夜精品久久久久久性色| 电影亚洲精品噜噜在线观看| 欧洲精品一区色| 日本欧美一区二区| 日本黄色免费片| 欧美一区二区三区视频在线| 狂野欧美性猛交xxxxx视频| 成人18视频| 国产视频久久| www.日本高清视频| 欧美精品在线观看播放| 91网址在线观看| 国产女人水真多18毛片18精品| 亚洲国产高清视频| 久久精品老司机| 欧美制服丝袜第一页| 国产在线1区| 国产一区二区久久久| 久久久蜜桃一区二区人| 激情五月深爱五月| 日韩午夜电影av| 涩涩视频在线播放| 亚洲精品美女久久7777777| 国产乱码一区二区三区| 日韩精品久久久久久久| 亚洲天堂成人在线视频| 四虎精品在线观看| 男女日批视频在线观看| 国产亚洲美州欧州综合国| 97视频免费在线| 国自产精品手机在线观看视频| 亚州综合一区| 亚洲天堂国产视频| 午夜欧美大尺度福利影院在线看| 国产女人在线视频| 97超碰资源| 日韩在线一区二区三区| 欧美日韩一级大片| 亚洲美女久久久| 国产激情一区| 久草综合在线观看| 一区二区三区四区激情| 国产尤物视频在线| 91精品黄色| 日韩**一区毛片| 久久久久久福利| 色噜噜狠狠色综合网图区| 欧美日韩精品一区二区三区在线观看| 色婷婷综合网站| 精品久久久精品| av免费在线网站| 无码免费一区二区三区免费播放 | 国产日韩三区| 国精产品一区一区三区mba桃花 | 激情综合网最新| 波多野结衣大片|