Я не могу говорить с библиотеками, которые вы нашли, но ограничитель скорости неплотный контейнер довольно прост.Вам нужно какое-то общее транзакционное хранилище.Каждый сегмент (или ограничитель скорости) - это просто целое число и значение времени.Целое число - это количество капель в корзине в конкретное время.Каждый раз, когда вам нужно применить ограничение скорости, вычтите количество капель, которые просочились с момента последнего обновления, затем добавьте одну, а затем проверьте, находится ли количество капель в пределах емкости.
Мы используемRedis для такого рода вещей.Чтобы сделать эту транзакцию в Redis, необходим скрипт (см. SCRIPT LOAD и EVALSHA ).В базе данных SQL, например, SELECT FOR UPDATE
, за которым следует оператор 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 капель в секунду с пропускной способностью 10 капель:
EVALSHA <SHA_IN_HEX> 1 rate-limit:my-bucket 10 10
Скрипт возвращает количество капель в корзине.Если это число равно емкости, вы можете либо спать в течение короткого периода времени и повторить попытку, либо отклонить запрос напрямую, в зависимости от ваших требований.
Обратите внимание, что сценарий никогда не возвращает значение, большее емкостиВ результате в вашем случае время восстановления составляет не более одной десятой секунды.Это может быть не то, что вам нужно, так как вы пытаетесь соответствовать стороннему ограничителю скорости.То есть вы можете быть в порядке с переполнением корзины, что приведет к увеличению времени восстановления после пакета запросов.