日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
如何實現(xiàn)計數(shù)器限流?

上一篇文章 go-zero 是如何做路由管理的? 介紹了路由管理,這篇文章來說說限流,主要介紹計數(shù)器限流算法,具體的代碼實現(xiàn),我們還是來分析微服務(wù)框架 go-zero 的源碼。

良慶網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián)公司,良慶網(wǎng)站設(shè)計制作,有大型網(wǎng)站制作公司豐富經(jīng)驗。已為良慶1000+提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站建設(shè)要多少錢,請找那個售后服務(wù)好的良慶做網(wǎng)站的公司定做!

在微服務(wù)架構(gòu)中,一個服務(wù)可能需要頻繁地與其他服務(wù)交互,而過多的請求可能導(dǎo)致性能下降或系統(tǒng)崩潰。為了確保系統(tǒng)的穩(wěn)定性和高可用性,限流算法應(yīng)運(yùn)而生。

限流算法允許在給定時間段內(nèi),對服務(wù)的請求流量進(jìn)行控制和調(diào)整,以防止資源耗盡和服務(wù)過載。

計數(shù)器限流算法主要有兩種實現(xiàn)方式,分別是:

  1. 固定窗口計數(shù)器
  2. 滑動窗口計數(shù)器

下面分別來介紹。

固定窗口計數(shù)器

算法概念如下:

  • 將時間劃分為多個窗口;
  • 在每個窗口內(nèi)每有一次請求就將計數(shù)器加一;
  • 如果計數(shù)器超過了限制數(shù)量,則本窗口內(nèi)所有的請求都被丟棄當(dāng)時間到達(dá)下一個窗口時,計數(shù)器重置。

圖片

固定窗口計數(shù)器是最為簡單的算法,但這個算法有時會讓通過請求量允許為限制的兩倍。

圖片

考慮如下情況:限制 1 秒內(nèi)最多通過 5 個請求,在第一個窗口的最后半秒內(nèi)通過了 5 個請求,第二個窗口的前半秒內(nèi)又通過了 5 個請求。這樣看來就是在 1 秒內(nèi)通過了 10 個請求。

滑動窗口計數(shù)器

算法概念如下:

  • 將時間劃分為多個區(qū)間;
  • 在每個區(qū)間內(nèi)每有一次請求就將計數(shù)器加一維持一個時間窗口,占據(jù)多個區(qū)間;
  • 每經(jīng)過一個區(qū)間的時間,則拋棄最老的一個區(qū)間,并納入最新的一個區(qū)間;
  • 如果當(dāng)前窗口內(nèi)區(qū)間的請求計數(shù)總和超過了限制數(shù)量,則本窗口內(nèi)所有的請求都被丟棄。

圖片

滑動窗口計數(shù)器是通過將窗口再細(xì)分,并且按照時間滑動,這種算法避免了固定窗口計數(shù)器帶來的雙倍突發(fā)請求,但時間區(qū)間的精度越高,算法所需的空間容量就越大。

go-zero 實現(xiàn)

go-zero 實現(xiàn)的是固定窗口的方式,計算一段時間內(nèi)對同一個資源的訪問次數(shù),如果超過指定的 limit,則拒絕訪問。當(dāng)然如果在一段時間內(nèi)訪問不同的資源,每一個資源訪問量都不超過 limit,此種情況是不會拒絕的。

而在一個分布式系統(tǒng)中,存在多個微服務(wù)提供服務(wù)。所以當(dāng)瞬間的流量同時訪問同一個資源,如何讓計數(shù)器在分布式系統(tǒng)中正常計數(shù)?

這里要解決的一個主要問題就是計算的原子性,保證多個計算都能得到正確結(jié)果。

通過以下兩個方面來解決:

  • 使用 redis 的 incrby 做資源訪問計數(shù)
  • 采用 lua script 做整個窗口計算,保證計算的原子性

接下來先看一下 lua script 的源碼:

// core/limit/periodlimit.go

const periodScript = `local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local current = redis.call("INCRBY", KEYS[1], 1)
if current == 1 then
    redis.call("expire", KEYS[1], window)
end
if current < limit then
    return 1
elseif current == limit then
    return 2
else
    return 0
end`

主要就是使用 INCRBY 命令來實現(xiàn),第一次請求需要給 key 加上一個過期時間,到達(dá)過期時間之后,key 過期被清楚,重新計數(shù)。

限流器初始化:

type (
    // PeriodOption defines the method to customize a PeriodLimit.
    PeriodOption func(l *PeriodLimit)

    // A PeriodLimit is used to limit requests during a period of time.
    PeriodLimit struct {
        period     int  // 窗口大小,單位 s
        quota      int  // 請求上限
        limitStore *redis.Redis
        keyPrefix  string   // key 前綴
        align      bool
    }
)

// NewPeriodLimit returns a PeriodLimit with given parameters.
func NewPeriodLimit(period, quota int, limitStore *redis.Redis, keyPrefix string,
    opts ...PeriodOption) *PeriodLimit {
    limiter := &PeriodLimit{
        period:     period,
        quota:      quota,
        limitStore: limitStore,
        keyPrefix:  keyPrefix,
    }

    for _, opt := range opts {
        opt(limiter)
    }

    return limiter
}

調(diào)用限流:

// key 就是需要被限制的資源標(biāo)識
func (h *PeriodLimit) Take(key string) (int, error) {
    return h.TakeCtx(context.Background(), key)
}

// TakeCtx requests a permit with context, it returns the permit state.
func (h *PeriodLimit) TakeCtx(ctx context.Context, key string) (int, error) {
    resp, err := h.limitStore.EvalCtx(ctx, periodScript, []string{h.keyPrefix + key}, []string{
        strconv.Itoa(h.quota),
        strconv.Itoa(h.calcExpireSeconds()),
    })
    if err != nil {
        return Unknown, err
    }

    code, ok := resp.(int64)
    if !ok {
        return Unknown, ErrUnknownCode
    }

    switch code {
    case internalOverQuota: // 超過上限
        return OverQuota, nil
    case internalAllowed:   // 未超過,允許訪問
        return Allowed, nil
    case internalHitQuota:  // 正好達(dá)到限流上限
        return HitQuota, nil
    default:
        return Unknown, ErrUnknownCode
    }
}

上文已經(jīng)介紹了,固定時間窗口會有臨界突發(fā)問題,并不是那么嚴(yán)謹(jǐn),下篇文章我們來介紹令牌桶限流。

以上就是本文的全部內(nèi)容,如果覺得還不錯的話歡迎點(diǎn)贊,轉(zhuǎn)發(fā)和關(guān)注,感謝支持。

參考文章:

  • https://juejin.cn/post/6895928148521648141
  • https://juejin.cn/post/7051406419823689765
  • https://www.infoq.cn/article/Qg2tX8fyw5Vt-f3HH673

文章名稱:如何實現(xiàn)計數(shù)器限流?
標(biāo)題來源:http://m.5511xx.com/article/dhichpe.html