flask limiter 實踐與原理解析

2021-09-12 07:11:12 字數 4149 閱讀 1186

乙個強大的軟體產品是由許多不同的元件結合完成的, 其中在每乙個產品中離不開的就是api系統, api系統在整個產品中居於中樞地位, 包括系統內部元件, 及客戶對產品的對接都要與api打交道, 這就需要最大限度的提高api的處理能力, 並且防範無效請求, 還有黑客的惡意攻擊。

限流可以在nginx層進行設定, 當然在api業務層做更加靈活、簡便, 今天就講述下flask_limiter在flask應用中的使用。

flask_limiter 是對limiter庫包裝成flask的擴充套件元件。 提供對flask訪問路徑的頻率限制。 對於其後端資料儲存有三種方式可供選擇:

1. 初始乙個limiter物件, 相關引數後續會做詳細介紹, 圖中的key_func引數是你的限制策略關鍵字, 上圖是對訪問的源ip做了限制,

在我們的業務中是針對於客戶id做了訪問限制, 這個根據業務需要自己決定, default_limits 是具體的限制策略內容也就是頻率, 這個配置是全域性配置會對flask的所有url生效

2.  在每個url的view中新增decorator, 上圖出現了兩種limiter.limit 設定限制的頻率, 此處的優先順序高於default_limits,

limiter.exempt 遮蔽限制策略。

10 per hour 以 'per' 為分隔符; 10/hour 以'/'做分隔符;10/hour;100/day;2000 per year 以『;』分隔設定多個,

100/day, 500/7days  可以新增複數

limiter.limit()

1. 單個

@limiter.limit("100/day;10/hour;1/minute")

def my_route()

2. 多個

@limiter.limit("100/day")

@limiter.limit("10/hour")

@limiter.limit("1/minute")

def my_route():

...3. 對單個url指定策略key值

def my_key_func():

[email protected]("100/day", my_key_func)

def my_route():

...

4. 動態獲取頻率限制策略(在策略需要從資料庫或者遠端api獲取的情況下使用)

def rate_limit_from_config():

@limiter.limit(rate_limit_from_config)

def my_route():

...

5. 一些特定情況下遮蔽策略(比如是超級使用者請求)

@limiter.limit("100/day", exempt_when=lambda: current_user.is_admin)

def expensive_route():

...limiter.shared_limit() 共享限制策略

1. 定義

mysql_limit = limiter.shared_limit("100/hour", scope="mysql")

@mysql_limit

def r1():

...@mysql_limit

def r2():

...

2. 動態共享限制策略(scope不指定的時候預設是endpoint_name-『%s.%s』 %(obj.__module__, obj.__name__))

def host_scope(endpoint_name):

return request.host

host_limit = limiter.shared_limit("100/hour", scope=host_scope)

@host_limit

def r1():

...@host_limit

def r2():

...

3. tip

limiter.exempt() (遮蔽策略)

limiter.request_filter()(符合條件的遮蔽策略)

@limiter.request_filter

def header_whitelist():

return request.headers.get("x-internal", "") == "true"

@limiter.request_filter

def ip_whitelist():

return request.remote_addr == "127.0.0.1"

ratelimit_default       預設策略, 逗號分隔('1/minute,100/hour'), 只要存在其他配置會失效

ratelimit_storage_urlmemory://orredis://host:portormemcached://host:port, 後端儲存資料的方式。

ratelimit_storage_options  dict型別,limits.storage.storage子類, 比如 。

ratelimit_strategyfixed-window 或者fixed-window-elastic-expiry 或者moving-window, 後續對三種模式詳細講解。

ratelimit_enabled      是否應用速率限制策略, 預設true

ratelimit_headers_enabled 是否返回速率限制的相關資訊到reponse header中預設false

ratelimit_header_limit,ratelimit_header_reset,ratelimit_header_remaining,ratelimit_header_retry_after對應配置上邊的header的鍵值字串。

ratelimit_swallow_errors 預設false即可

ratelimit_in_memory_fallback 後端儲存異常使用的策略配置

ratelimit_key_prefix  儲存key的字首配置

1.fixed-window (固定視窗)

以5/minute為例

由圖可以看出, 第一次hit到url時新增key, 類似"limiter/key_function/live_api.live_numbers/5/1/minute"的鍵值,預設值為0, 在週期內請求超過5次, 後續請求全部返回429, 第二個週期開始時key會被清除, 如此往復。

缺點:大量請求可以集中在乙個週期的結束時,及下乙個週期的開始, 黑客可以集中在這段時間攻擊系統。

2.fixed-window-elastic-expiry(固定視窗的伸展週期)

與fixed-window區別在於, 每次hit到url時key的過期時間都會延續乙個週期, 如果在達到速率限制條件時持續請求將永遠不會成功, 必須停止請求超過一週期時間, 才可以繼續請求。

3. moving-window(移動視窗)

以5/minute為例

移動視窗策略在內部維護乙個列表,當列表的長度小於5時, 就不會滿足速率限制條件, 當長度大於5時, 比如[t6, t5, t4, t3, t2, t1], 此時就會拿出t1物件, 當t1的請求時的時間戳大於等於now-expiry時拒絕請求,在t1的存在於列表中的時間大於乙個週期就會被清除。

由此可以看出此策略動態維護乙個列表, 比如如果策略為2000/minite 那這樣可能是長度為2000的列表長度維護, 相比前兩種會有更大的記憶體花銷。

與專案實踐

模型 描述業務 業務規則 系統使用 應用程式 系統架構以及系統內互動的一種視覺化方式。便於理解業務 需求,理解軟體和架構如何構造。美國前 艾森豪威爾說 計畫是零,計畫的過程是一切。模型本身並不是最重要的,建立模型的過程和經歷得思考才是最具價值。建模可以強迫你去思考,通過充分的思考,你就可以做出最好的...

真理與實踐

下面片段的摘自柴靜天涯部落格 如果真理不大寫呢 絕大多數學科都包含思辨理性 實踐理性和技藝這三種知識,但由於對知識傳統所形成的思維定勢,我們更多地把視線投向普適化的知識 大寫的真理,其他兩種的知識得不到正當化。朱蘇力說 許多人習慣了標籤式的思維,把中國基層司法實踐中的不同問題都闡釋為法治不健全 法官...

React Native 研究與實踐

github popular開發教程,原始碼解析,專案總結 react native 問題及解決方案合集 react native 效能優化 react native 每日一學 每天乙個知識點 技巧,經驗,填坑日記等 每天學一點,離大神近一點。react native 專案實踐總結 react na...