
Security News
CISA Kills Off RSS Feeds for KEVs and Cyber Alerts
CISA is discontinuing official RSS support for KEV and cybersecurity alerts, shifting updates to email and social media, disrupting automation workflows.
基于redis的限流器
pip install redis-limiter
陆陆续续写过不少基于redis的限流逻辑,看似简单,实际写下来还是有不少要留意的问题
以一个简单的功能为例:
限制每个用户一天内只能修改昵称3次
直观的想法很简单,伪代码如下:
key=user_id + date
if redis.get(key) >= 3:
return False
... operation logic ...
redis.incr(key)
然而仔细想下,事情没那么简单,上面的逻辑在并发请求的情况下,用户操作很容易会超出3个的限制;为解决这个问题,我们换个思路:
key = user_id + date
if redis.incr(key) > 3:
return False
...operation logic....
嗯,并发情况下不会超额了,问题是如果operation logic执行失败了呢,用户是不是就丢失了操作的配额? 这种情况是不是要把INCR的数值给减回来呢?
还有其他可能出现的问题:
嗯,基于redis的限流并没有直观的看上去那么简单
redis-limiter致力于解决上面的所有问题,提供一个通用的基于redis的限流器功能
使用redis-limiter实现上面的例子:
import redis-limiter
quota = 3
key_prefix = "operation_limit"
config = redis_limiter.Config(redis)
limiter = redis_limiter.FixedWindowLimiter(config, key_prefix, quota, '1d')
limit_key = user_id
target = limiter.target(limit_key)
target.acquire()
is_suc = False
try:
...operation logic...
is_suc = True
finally:
if is_suc:
target.apply()
else:
target.release()
留意上面的acquire,表示预扣一个限额指标,业务逻辑执行成功,则执行apply使用掉改指标,如果失败则release释放该指标; 如果acquire之后什么都不做,则经过一定的超时时间自动释放
acquire会先检查已扣的数量是否满额,如果是,则raise redis_limiter.AcquireFullException acquire之后会检查已扣的数量 + 预扣的数据,看是否满额,如果是,则raise redis_limiter.AcquirePendingFullException
对于raise redis_limiter.AcquirePendingFullException,还可以加上指定的block time, 即等待其他现成release指标,等待超过指定block time,才raise该异常; 在limiter对象创建时,使用block参数指定超时时间,单位是秒:
limiter = redis_limiter.FixedWindowLimiter(config, key_prefix, quota, '1d', block=10)
需要留意的时,block功能是使用redis的stream数据结构实现的,需要redis server的版本>=5.0; 如果使用的版本低于5.0则无法使用block功能,并在需要指定config参数: support_blocking=False
eg:
config = redis_limiter.Config(redis, support_blocking=False)
limiter支持使用with语句, 上面的demo中acquire之后的代码,可以改为如下写法:
with limiter.target(limit_key) as target:
...opeation logic...
这种写法,执行无异常会自动apply,异常则自动release,也可以在with的代码块中,手动apply/release:
with limiter.target(limit_key) as target:
is_suc = ...opeation logic...
if is_suc:
target.apply()
else:
target.release()
redis-limiter实现了4种类型的限流器
除了Semaphore,其他几种限流器都需要指定一个时间周期,比如10秒、1天。。。 reids_limiter使用了统一的字符串格式指定时间周期:数字+单位后缀,比如"10s"表示10秒,"10min"表示10分钟,所有的后缀如下:
init函数:
def __init__(self, config, key_prefix, quota, period, block=0, pending_ex=20)
IntervalLimiter实现指定时间间隔内不超过某限额的功能,时间精确到秒; 比如指定 period="1d", quota=3, 不是表示1个自然日内的限额是3,而是表示任何24*3600秒的时间段内限额为3
init函数:
def __init__(self, config, key_prefix, quota, period, block=0, pending_ex=20)
FixedWindowLimiter实现基于固定时间窗口计数的限流功能; period统一按照自然时间,比“1min"表示每自然分钟,"1d"表示每自然日,"1mo"表示每个自然月,所以period会有些限制; 比如日期单位的数量只能是1,即只能是"1d", 不能是"2d", "10d"或其他任意大于1的数量,因为每月或每年的天数是不固定的,没法取key; 而秒单位的则可以取,"5s", "10s"... , 单要求必须是60(1分钟60秒)的约数 period数量完整的约束如下:
init函数:
def __init__(self, config, key_prefix, quota, period, block=0, pending_ex=20)
SlideWindowLimiter实现了基于滑动窗口计数的限流功能,计数的窗口数量不需要在参数中自定,而是自动计算: 取<=10并且最接近10的值
类似FixedWindowLimiter,period也会有一些约束, 假定我们把period数量值表示为$v,则规则如下表示:
init函数:
def __init__(self, config, key_prefix, quota, block=0, pending_ex=20)
Semaphore用于限定同一时间的并发处理数量,相比其他限流器有些不同:
FAQs
A Redis based rate limiter implementation for Python
We found that redis-limiter demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
CISA is discontinuing official RSS support for KEV and cybersecurity alerts, shifting updates to email and social media, disrupting automation workflows.
Security News
The MCP community is launching an official registry to standardize AI tool discovery and let agents dynamically find and install MCP servers.
Research
Security News
Socket uncovers an npm Trojan stealing crypto wallets and BullX credentials via obfuscated code and Telegram exfiltration.