2 回答

TA貢獻1995條經(jīng)驗 獲得超2個贊
我無法與您找到的庫交談,但漏桶速率限制器非常簡單。您需要某種共享事務(wù)存儲。每個存儲桶(或速率限制器)只是一個整數(shù)和一個時間值。該整數(shù)是特定時間桶中的滴數(shù)。每次必須應(yīng)用速率限制時,減去自上次更新以來泄漏的滴數(shù),然后加一,然后檢查滴數(shù)是否在桶的容量范圍內(nèi)。
我們正在使用 Redis 來完成這類事情。要在 Redis 中實現(xiàn)此事務(wù)性,需要一個腳本(。例如,在 SQL 數(shù)據(jù)庫中,aSELECT FOR UPDATE
后跟一條語句可以實現(xiàn)相同的效果。UPDATE
這是我們的 Redis 腳本:
-- replicate_commands allows us to use the TIME command. We depend on accurate
-- (and reasonably consistent) timestamps. Multiple clients may have
-- inacceptable clock drift.
redis.replicate_commands()
local rate = tonumber(ARGV[1]) -- how many drops leak away in one second
local cap = tonumber(ARGV[2]) -- how many drops fit in the bucket
local now, _ = unpack(redis.call('TIME'))
-- A bucket is represented by a hash with two keys, n and t. n is the number of
-- drops in the bucket at time t (seconds since epoch).
local xs = redis.call('HMGET', KEYS[1], 'n', 't')
local n = tonumber(xs[1])
local t = tonumber(xs[2])
if type(n) ~= "number" or type(t) ~= "number" then
? ? -- The bucket doesn't exist yet (n and t are false), or someone messed with
? ? -- our hash values. Either way, pretend the bucket is empty.
? ? n, t = 0, now
end
-- remove drops that leaked since t
n = n - (now-t)*rate
if n < 0 then
? ? n = 0
end
-- add one drop if it fits
if n < cap then
? ? n = n + 1
else
? ? n = cap
end
redis.call('HMSET', KEYS[1], 'n', n, 't', now)
redis.call('EXPIRE', KEYS[1], math.floor(n/rate) + 1)
return n
每秒 10 滴的調(diào)用示例,容量為 10 滴:
EVALSHA <SHA_IN_HEX> 1 rate-limit:my-bucket 10 10?
該腳本返回桶中的滴數(shù)。如果該數(shù)字等于容量,您可以短暫休眠并重試,或者完全拒絕該請求,具體取決于您的要求。
請注意,腳本永遠不會返回大于容量的值,因此在您的情況下恢復(fù)時間不會超過十分之一秒。這可能不是您所需要的,因為您正在嘗試匹配第三方速率限制器。也就是說,您可能可以接受桶溢出,從而導(dǎo)致突發(fā)請求后恢復(fù)時間更長。

TA貢獻1777條經(jīng)驗 獲得超3個贊
如果你想要一個全局速率限制器,你需要一個地方來維護分布式狀態(tài),比如zookeeper。通常,我們不想支付管理費用?;蛘撸梢栽O(shè)置轉(zhuǎn)發(fā)代理,在其中進行速率限制。
- 2 回答
- 0 關(guān)注
- 192 瀏覽
添加回答
舉報