redis set nx
set数据结构
-1 永久存在
-2 过期已删除或者是键不存在
redis命令参考
https://redis.io/commands/set/
redis键值的计数
- key先设置值后设置过期时间
clear
flushall
get a
set a 1
get a
ttl a
expire a 10
get a
ttl a
- 使用nx对key进行设置
flushall
get a
ttl a
set a 1 nx ex 10
incr a
get a
ttl a
get a
ttl a
- 若key存在使用setnx设置key的值增加过期时间
flushall
get a
ttl a
set a 10
get a
ttl a
set a 1 nx ex 10
get a
ttl a
setnx中set的值不生效,且设置的过期时间不生效
- 先setnx 再set
flushall
get a
ttl a
set a 1 nx ex 10
get a
ttl a
set a 10
get a
ttl a
get a
ttl a
setnx 中设置的过期时间不生效,后set设置的值生效
incr 自增
- 原始的键值不存在
flushall
get a
ttl a
incr a
get a
ttl a
incr a
get a
ttl a
键若不存在,则键默认值为0,每incr一次+1
- 原始的键值存在,且不为0
flushall
set a 3
get a
ttl a
incr a
get a
ttl a
incr a
get a
ttl a
- 若健存在,且数据类型为字符串
flushall
set a k
get a
ttl a
incr a
get a
ttl a
incr a
get a
ttl a
- m分钟n次计数实现
flushall
set a 1
expire a 10
get a
ttl a
incr a
get a
ttl a
incr a
get a
ttl a
分析:该操作set 和 expire 将分为两个命令对数据库进行操作
flushall
set a 1 nx ex 10
ttl a
incr a
get a
ttl a
incr a
get a
ttl a
分析:该操作将set 和 expire 同时进行执行
import redis
import time
# 连接到Redis
r = redis.Redis(host="localhost", port=6379, db=0)
def slidingWindow(mykey):
"""
滑动窗口计数
频率统计,统计当前key来过的次数
"""
lua_script = """
local window_start_time = ARGV[1] - ARGV[3]*1000
-- 先把统计窗口之前的所有数据都给删掉
redis.call('ZREMRANGEBYSCORE',KEYS[1],'-inf',window_start_time)
-- 在这里把当前这次的请求加入到有序set中
redis.call('ZADD',KEYS[1],ARGV[1],ARGV[1])
-- 获取到增加后的有序set中当前key的个数
local now_request = redis.call('ZCARD',KEYS[1])
return now_request
"""
# 时间窗口的大小
time_windows = 10
# 获取当前的时间戳到ms
currentTime = int(time.time() * 1000)
# 限制的次数
limit = 3
# 调用lua的脚本返回数据库中统计的最近几分钟里这个key出现的次数
result = r.eval(lua_script, 1, mykey, currentTime, limit, time_windows)
return result
def fixedWindow(mykey):
"""
固定窗口计数
给定一个key统计m分钟n次的次数
查看key是否存在,存在+1
不存在就设置为1,设置一个key,设置值为1,设置过期时间
时间窗口默认是S
"""
time_windows = 10
ttl_mykey = r.ttl(mykey)
if ttl_mykey > 0:
# 键存在时候也要设置过期时间
incr_after = r.incr(mykey, 1)
# 但是这样设置就会在在每次执行的时候都会设置成当前时间往后的固定10s时间过期
# 如果是业务场景中,某一个用户,被封之后如果一直请求,然后一直会被封掉,过期时间会一直往后延长
else:
# 设置当前这个键的值为1
# r.setnx(mykey, 1)
# 设置当前这个键的过期时间为10s
r.setex(mykey, time_windows, 1)
# 第一时候则默认值设置为1
incr_after = 1
return incr_after
https://gitee.com/gunhe/system_celery/blob/master/fastapi_demo/project_template/tools/tool_redis.py