Redis-Key的生存时间

本文介绍Redis中如何利用时效性Key解决网站访问频率限制等问题,包括expire、ttl和persist等命令的使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在实际开发过程中,经常会遇到一些有实效性的数据,比如限时优惠、缓存、验证码等等,过了一段时间后就应该删除这些数据。如果用关系型数据库,那么就需要在表中增加一个字段存储实效时间,然后定时轮询该字段并判断删除。而在redis中,可以使用expire命令给key设置有效时间来实现这个需求。

操作命令

expire key seconds    #设置key的有效时间  单位为秒
ttl key               #获取key的剩余有效时间
persist key           #设置有时效性的key为持久key

注意,对有实效性的key使用set会字段取消实效设置,变成持久key。

示例:

127.0.0.1:6379> set session:a34d zhangsan
OK
127.0.0.1:6379> expire session:a34d 20
(integer) 1
127.0.0.1:6379> ttl session:a34d
(integer) 2
127.0.0.1:6379> ttl session:a34d
(integer) -2
127.0.0.1:6379> get session:a34d
(nil)
127.0.0.1:6379> set session:a34d 40
OK
127.0.0.1:6379> ttl session:a34d
(integer) -1
127.0.0.1:6379> expire session:a34d 30
(integer) 1
127.0.0.1:6379> ttl session:a34d
(integer) 22
127.0.0.1:6379> persist session:a34d
(integer) 1
127.0.0.1:6379> ttl session:a34d
(integer) -1
127.0.0.1:6379> get session:a34d
"40"
127.0.0.1:6379> 

实践

1)限制具体IP在某个时段内的访问次数
有时,出于对网站的保护,我们需要对同一个ip的访问频率做出限制,以防止黑客攻击、网络爬虫给网站造成负载过大甚至崩溃。

对于这个需求,利用具有时效性的key就可以很好的解决。例如,限制每个用户每分钟最多访问网站100次,对应的思路就是:

对每一个用户创建一个名为rate.limiting:userip的键
设置改键的生存时间为1分钟
每次用户访问时,首先读取这个键的键值
判断是否超过100
使用incr命令将该键值+1
有效时间到,键自动删除
用户再访问时,重建该键,循环往复

伪代码如下:

$isKeyExists = exists rate.limiting:$ip
#如果存在
if $isKeyExists is 1
    $times = incr rate.limiting:$ip
    if $times > 100
        print "post limit"
        exit
else
    incr rate.limiting:$ip   #自动创建并初始值1
    expire rate.limiting:$ip 60

上面的代码有一个非常严重的潜在问题,如果成行在运行完inr rate.limiting:$ip后因为某种原因退出了,那么这个key就没有被设置有效时间,此后,这个ip在访问网站时,就会跳过访问频率的限制。

我们可以利用reids提供的事务能力对上面的代码进行改写

$isKeyExists = exists rate.limiting:$ip
#如果存在
if $isKeyExists is 1
    $times = incr rate.limiting:$ip
    if $times > 100
        print "post limit"
        exit
else
    mulit
        incr rate.limiting:$ip   #自动创建并初始值1
        expire rate.limiting:$ip 60
    exec
### 使用 Redis 防止超卖的解决方案 #### 1. 利用 SETNX 和过期时间设置分布式锁 为了确保在高并发情况下不会发生超卖现象,可以通过 `SETNX` (Set if Not Exists) 命令配合 expire 时间来创建一个分布式的锁。这种方式能够有效避免多个请求同时修改同一份资源。 ```bash SET resource_name lock_value NX PX 10000 ``` 这条命令表示只有当键不存在时才对其进行设值操作,并设定其存活时间为10秒(PX参数),以此防止死锁的发生[^1]。 #### 2. 库存扣减逻辑设计 针对具体的商品库存管理,在接收到购买请求后应立即尝试获取对应的锁。成功获得锁之后再查询实际剩余数量并判断是否允许此次交易继续进行下去: - 如果有足够的存货,则更新数据库中的记录; - 否则拒绝订单并向用户返回错误提示信息。 此过程需尽可能缩短持有锁的时间长度以减少其他客户的等待延迟[^4]。 #### 3. 处理异常情况下的解锁 考虑到程序运行期间可能出现的各种意外状况(如网络中断),应当有相应的措施保证即使是在这些特殊条件下也能正常释放已占用的锁定状态。这通常涉及到监听连接断开事件或是定期检测长时间未被使用的锁实例以便及时清理它们[^5]。 ```python import redis from contextlib import contextmanager client = redis.Redis(host='localhost', port=6379, db=0) @contextmanager def acquire_lock(lock_key, timeout=10): identifier = str(uuid.uuid4()) status = client.set(lock_key, identifier, nx=True, ex=timeout) try: yield status is not None and client.get(lock_key).decode() == identifier finally: if client.exists(lock_key) and client.get(lock_key).decode() == identifier: client.delete(lock_key) with acquire_lock('item_stock'): # 执行库存检查与扣除业务逻辑... pass ``` 上述代码片段展示了如何利用 Python 的上下文管理器简化对 Redis 锁机制的应用,使得开发者可以在更安全可控的方式下调用相关功能接口。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值