1 背景
限流是生產(chǎn)中經(jīng)常遇到的一個場景, 目前現(xiàn)有的一個工具大部分是提供單機(jī)限流的能力, 例如 google 的 guava 中提供的 RateLimiter. 但是生產(chǎn)環(huán)境大部分是分布式環(huán)境, 在多臺機(jī)器的環(huán)境下, 需要的是能對多臺機(jī)器一起限流的分布式限流。 分布式限流依賴公共的后端存儲, 所以還需要自己搭建。
2 算法
說到限流, 首先依賴的是限流的算法, 限流的算法很多包括令牌桶, 漏桶。
滑動窗口
滑動窗口算法的優(yōu)點(diǎn)在于可以在滑動時間內(nèi)計算出相對精確的限流數(shù)據(jù)。 想象一個簡單的限流算法, 例如限制在一分鐘內(nèi)最多訪問 10 次。 我們在后端存儲的結(jié)構(gòu)如下
假設(shè)每個框代表了一分鐘, 框中存儲了一分鐘內(nèi)的限流數(shù)據(jù), 那么問題在于我們想要紅色框的限流的數(shù)據(jù)時將無法計算, 也就是說我們的限流的時間節(jié)點(diǎn)的起止時間是固定的。 而滑動窗口之所以為“滑動”, 則是為了解決這個問題誕生。 而實(shí)際上, 這個方法也是令牌桶的一種變相實(shí)現(xiàn)。
滑動實(shí)現(xiàn)的核心思想, 在于將時間塊切分到更細(xì)的精度, 假如我們繼續(xù)將 1 分鐘切分為更小的維度, 例如 5 秒, 那么以后我們的頻率計算的時間節(jié)點(diǎn)就可以變得更精確, 例如 10:11:00 ~ 10:12:00, 10:11:05 ~ 10:12:05, 10:11:10 ~ 10:12:10 。。。 做到 5 秒的精度, 如圖
從另一個角度來講, 一分鐘時間的間隔, 實(shí)際上也是一種滑動的特殊情況, 只不過精度一分鐘。
3 后端存儲
既然說到分布式實(shí)現(xiàn), 則需要考慮公共的后端存儲服務(wù), 此處我們選擇 redis, 因?yàn)?redis 提供了方便的數(shù)據(jù)結(jié)構(gòu)供我們實(shí)現(xiàn)滑動窗口, 主要會用到 redis 中的 map. 具體實(shí)現(xiàn)可以參照代碼。
實(shí)現(xiàn)
為了保證單次限流各種操作的原子性, 我們選擇使用 lua 腳本執(zhí)行限流邏輯, 最終會返回是否達(dá)到流量限制的結(jié)果。
key : 限流記錄的 key, 此處的 key 由外部傳入, 一般根據(jù)我們需要限流的維度來生成。 例如如果是按 ip 對某個 url 做訪問限流限制, 則 key 可能是 url:/test:ip:192.168.1.1
current time : 當(dāng)前時間, 使用服務(wù)端 redis 時間, 為了保證分布式情況下時間的一致性, 這里的使用通過 redis.time 獲取并傳入 lua 腳本
duration : 限流的總時長, 例如 1 分鐘則是 60 * 1000 ms
limitation : 最高流量限制, 例如每分鐘 10 次, 則為 10
precision : 限流精度, 例如精度是 1s, 則為 1000 ms, 限流精度也是保證能實(shí)現(xiàn)上圖紅框內(nèi)限流的關(guān)鍵, 精度越小, 限流越精確, block 數(shù)也越多, 占用的內(nèi)存也越大。 實(shí)際上上圖的簡單限流即是 duration = precision 的一種特殊情況
permits : 本次需要增加多少流量, 對于頻率來說一般是 1, 而對于流量來說則是數(shù)據(jù)流量的字節(jié)數(shù)
4 考慮的問題
redis 集群問題
由于 redis 是集群環(huán)境, 集群環(huán)境下實(shí)際上直接執(zhí)行 lua 腳本是有問題的。 試想 lua 腳本內(nèi)可能涉及到多個 key 的操作, 而 redis 實(shí)際執(zhí)行節(jié)點(diǎn)的選擇也是通過 key 來選擇的。 在多 key 情況下可能會造成 lua 腳本內(nèi) key 的執(zhí)行混亂, 所以我們需要先手動選擇好 redis 節(jié)點(diǎn)。
此處我們可以先用限流的 key 將 redis 選擇出來, 再將 lua 腳本傳到某個 redis 節(jié)點(diǎn)執(zhí)行。 也就是我們必須要可以通過限流 key 唯一確定一個 redis 節(jié)點(diǎn), 例如 url:/test:ip:192.168.1.1 是可以確定使用某個 redis 節(jié)點(diǎn)的。
分布式時間問題
分布式系統(tǒng)需要考慮多客戶端時間不一致問題, 此處使用 redis 時間解決。
客戶端性能問題
由于這是一個公用的限流服務(wù), 也就是所有接入該服務(wù)的應(yīng)用的每次請求都會調(diào)用該服務(wù), 再加上所有接入服務(wù)的應(yīng)用共用一個 redis, 顯然如果客戶端使用同步等待限流服務(wù)的返回結(jié)果并不太合適, 會影響客戶端的服務(wù)調(diào)用性能。
所以我們可以使用一種折中策略, 即將限流結(jié)果保存到本地, 每次請求直接檢查本地限流結(jié)果是否被限流, 同時使用異步的方式調(diào)用限流服務(wù), 并在異步回調(diào)中更新限流結(jié)果。 這種做法會讓限流數(shù)據(jù)略有延遲, 但是影響不大。
限流服務(wù)本身的負(fù)載
作為限流服務(wù), 一個主要的作用是限制惡意流量對正常業(yè)務(wù)造成沖擊, 但如果所有流量都需要經(jīng)過限流服務(wù), 當(dāng)流量激增的時候, 誰來保證限流服務(wù)自己不被壓垮? 我的建議是設(shè)定一個閾值, 當(dāng)流量超過某個閾值(一般來講, 這個閾值可以設(shè)置為 機(jī)器數(shù) * 限流閾值)時, 直接退化為本地限流。
-
lua腳本
+關(guān)注
關(guān)注
0文章
24瀏覽量
7779 -
Redis
+關(guān)注
關(guān)注
0文章
390瀏覽量
11853
發(fā)布評論請先 登錄

分布式軟件系統(tǒng)
LED分布式恒流原理
分布式發(fā)電技術(shù)與微型電網(wǎng)
分布式聲波傳感系統(tǒng)DAS
如何設(shè)計分布式干擾系統(tǒng)?
分布式系統(tǒng)的優(yōu)勢是什么?
HarmonyOS應(yīng)用開發(fā)-分布式設(shè)計
各種分布式電源的電氣特性
如何高效完成HarmonyOS分布式應(yīng)用測試?
分布式電源分布式電源裝置是指什么?有何特點(diǎn)
OpenHarmony3.1分布式技術(shù)資料合集
常見的分布式供電技術(shù)有哪些?
Redis實(shí)現(xiàn)分布式多規(guī)則限流的方式介紹

評論