基於Redis的限流實現方式

一、什麼是限流

在計算機系統中,流量控制(Flow Control)是指通過對數據的傳輸速率、數據量或者數據傳輸速度等進行控制和限制,以避免數據因為太快、太多而導致系統癱瘓、崩潰等問題。限流是流量控制的一種常見方法,常用於保護系統免於被大量的請求耗盡資源或者被攻擊。

二、為什麼需要限流

隨著互聯網行業的迅速發展,數據的存取和傳輸量越來越大,具有「爆炸性增長」的特點。針對這種情況,限流的存在是必不可少的,特別是在面對一些高並發場景時,如果沒有限流可能導致系統崩潰甚至服務宕機。

三、常見的限流演算法

1. 固定窗口演算法

固定窗口演算法是一種最簡單的計數器演算法,即某個時間窗口內只能處理一定數量的請求,如果到達這個計數器的上限,其他請求就被拒絕,這種演算法可以使用計數器實現,當計數器的數量達到限制時,就拒絕其他請求。

例如,設置一個固定的時間窗口(比如1秒鐘),對於這個時間窗口內,最多只能處理n個請求(比如100個),超過這個數量的請求就直接被拒絕,不會被處理。

/*redis實現固定窗口演算法*/
def is_action_allowed(action_key, action_count):
    with redis.client.pipeline() as pipe:
        pipe.set(action_key, 0, ex=time_window) /*先Set Zero*/
        pipe.incr(action_key)                           /*Incr (被調用就加1)*/
        pipe.execute()                                           /*執行*/
        return pipe.get(action_key) < action_count      /*UpLimiter*/

2. 滑動窗口演算法

固定窗口演算法有一個明顯的缺陷,如果在某個短時間內有大量請求到達,就會使得固定時間窗口內的總請求數過多,而滑動窗口演算法就是為了解決這個缺陷而出現的。滑動窗口演算法將時間窗口分成多個小窗口,每個小窗口的數量上限都和整個時間窗口的數量相等。

例如,將時間窗口分成10個小窗口,每個小窗口的上限為10個請求,那麼整個時間窗口內的請求上限就為100個請求。當有新來的請求時,就從右側進入並且移動,超出限制就直接被拒絕。

/*redis實現滑動窗口演算法*/
def is_action_allowed(action_key, action_count):
    with redis.client.pipeline() as pipe:
        timestamp = time.time() // time_window    /*當前unix時間戳*/
        pipe.zadd(action_key, {timestamp: timestamp})           
        pipe.zremrangebyscore(action_key, 0, timestamp - time_window)
    /*返回Interval */
        pipe.zcard(action_key)
        pipe.execute()
        return count <= action_count

3. 令牌桶演算法

令牌桶演算法是一種比較常用的限流演算法,它維護一個固定大小的令牌桶,以及一個容量固定的等待隊列,當有請求來臨時,如果桶內有足夠的令牌(也就是令牌桶處於「非空」狀態),就將其取出並處理;如果桶內沒有令牌(也就是令牌桶處於「空」狀態),則將請求加入到等待隊列中,等待下一次有令牌時再進行處理。

例如,設置令牌桶的容量為100,而這個令牌桶每秒鐘產生100個令牌。每來一個請求,就先去判斷當前令牌桶的令牌數量,如果桶中的令牌數量不夠,則拒絕這個請求,否則就將令牌數減1。

/*redis實現令牌桶演算法*/
def is_action_allowed(token_bucket_key, capacity, tokens_per_second):
    with redis.client.pipeline() as pipe:
        pipe.setnx(token_bucket_key, capacity)   /*setmax*/
        /*累加時,要求原始值在新值之前*/
        last_tokens, capacity = pipe.multi() \
                                            .get(token_bucket_key) \
                                            .strtol(tokens_per_second) \
                                            .execute() 
        if last_tokens + tokens_per_second < capacity:
            pipe.set(token_bucket_key, last_tokens + tokens_per_second)
        else:
            return False
        return True

四、如何使用Redis實現限流

Redis是一款高性能內存資料庫,而且具有豐富的功能,我們可使用Redis作為限流工具,來實現高並發下的限流。

1. 通過Redis的單線程模型進行限流

Redis的單線程模型設計並發的特性非常適合做限流,可以利用Redis的原子性和分散式特性使用Lua腳本快速實現限流邏輯。

def is_action_allowed(key, limit, expire=60):
    with redis.client.pipeline() as pipe:
        key = key + str(int(time.time()/expire))
        pipe.incr(key)
        pipe.expire(key, expire)
        pipe.execute()
        total = pipe.get(key)
        return total <= limit

2. 通過Redis+Lua實現令牌桶演算法

使用Lua腳本實現原子性的操作,並且減少了網路傳輸的時間延遲,也提供了更為方便的桶容量可控性和更細緻的訪問轉移控制。

redis.call()

五、結論

本文主要介紹了Redis在高並發場景下限流的常見演算法以及如何使用Redis來實現限流功能。限流的目的是保護系統免於被大量請求耗盡資源或者被攻擊,而Redis的特點適合限流這種高並發業務場景。希望本文能夠幫助到大家,也希望讀者在實際開發中選擇適合自己業務場景的限流演算法。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/272124.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-17 00:08
下一篇 2024-12-17 00:08

相關推薦

  • Python緩存圖片的處理方式

    本文將從多個方面詳細闡述Python緩存圖片的處理方式,包括緩存原理、緩存框架、緩存策略、緩存更新和緩存清除等方面。 一、緩存原理 緩存是一種提高應用程序性能的技術,在網路應用中流…

    編程 2025-04-29
  • 在CentOS上安裝Redis

    Redis是一款非關係型資料庫,它支持多種數據結構,包括字元串、哈希、列表、集合、有序集合等。Redis運行內存內並且支持數據持久化,它還可以應用於緩存、消息隊列等場景。本文將介紹…

    編程 2025-04-28
  • Python在線編輯器的優勢與實現方式

    Python在線編輯器是Python語言愛好者的重要工具之一,它可以讓用戶方便快捷的在線編碼、調試和分享代碼,無需在本地安裝Python環境。本文將從多個方面對Python在線編輯…

    編程 2025-04-28
  • Java表單提交方式

    Java表單提交有兩種方式,分別是get和post。下面我們將從以下幾個方面詳細闡述這兩種方式。 一、get方式 1、什麼是get方式 在get方式下,表單的數據會以查詢字元串的形…

    編程 2025-04-27
  • 解析spring.redis.cluster.max-redirects參數

    本文將圍繞spring.redis.cluster.max-redirects參數進行詳細闡述,從多個方面解讀它的意義與作用,並給出相應的代碼示例。 一、基礎概念 在介紹sprin…

    編程 2025-04-27
  • 用Pythonic的方式編寫高效代碼

    Pythonic是一種編程哲學,它強調Python編程風格的簡單、清晰、優雅和明確。Python應該描述為一種語言而不是一種編程語言。Pythonic的編程方式不僅可以使我們在編碼…

    編程 2025-04-27
  • Redis Bitmap用法介紹

    Redis是一款高性能的內存資料庫,支持多種數據類型,其中之一便是bitmap。Redis bitmap(點陣圖)是一種用二進位位來表示元素是否在集合中的數據結構。由於使用了二進位位…

    編程 2025-04-27
  • Java多版本支持實現方式

    本文將從以下幾個方面闡述如何實現Java多版本支持,並給出可行的代碼示例。 一、多版本Java環境概述 Java是一門跨平台的編程語言,但是在不同的應用場景下,可能需要使用不同版本…

    編程 2025-04-27
  • SpringBoot Get方式請求傳參用法介紹

    本文將從以下多個方面對SpringBoot Get方式請求傳參做詳細的闡述,包括URL傳參、路徑傳參、請求頭傳參、請求體傳參等,幫助讀者更加深入地了解Get請求方式下傳參的相關知識…

    編程 2025-04-27
  • Python獲取APP數據的多種方式

    如果您需要對APP進行分析、數據採集、監控或者自動化測試,那麼您一定需要獲取APP的數據。本文將會介紹一些Python獲取APP數據的方式。 一、使用ADB工具獲取APP數據 AD…

    編程 2025-04-27

發表回復

登錄後才能評論