redis“非持久化”临时令牌需靠ttl控制而非关闭rdb/aof——必须每个key显式设置ex/px过期时间,go客户端应使用set原子写入并传time.duration,验证删除须用lua脚本保证原子性。

Redis 本身不提供“非持久化”模式开关,所谓高速临时令牌寄存器,本质是靠合理配置 redis-server + 正确使用 SET 命令的过期策略实现的——不是靠关掉持久化,而是靠不让数据落盘、不让它活过业务生命周期。
为什么不能简单关闭 RDB/AOF 就算“非持久化”
关闭 save 指令或设 appendonly no 只是停掉落盘行为,但 Redis 内存数据仍可能因崩溃丢失(这是预期),更关键的是:没设过期时间的 key 会一直留在内存里,最终撑爆内存或导致误用。真正的“临时”,必须由每个 key 自带 TTL 控制生命周期。
-
CONFIG SET save ""或注释掉redis.conf中所有save行 → 防止 RDB 触发 -
CONFIG SET appendonly no→ 关闭 AOF(重启后数据全丢,符合“临时”语义) - 但必须在写入时显式指定
EX或PX参数,例如SET token:abc123 "uid:789" EX 300 - 不设 TTL 的 key 即使在无持久化模式下,也会持续占用内存,直到手动
DEL或服务重启
Go 客户端写入令牌时必须带 TTL,且避免用 SETNX 替代 SET EX
SETNX 不支持原生命令级过期,常见错误是先 SETNX 再 EXPIRE,这存在竞态窗口:若客户端写入成功但 EXPIRE 失败,key 就变成永生状态。Golang 使用 github.com/go-redis/redis/v9 时应直接调用 Set 并传入 time.Duration:
ctx := context.Background()
err := rdb.Set(ctx, "token:"+tokenID, userID, 5*time.Minute).Err()
if err != nil {
// 处理连接或命令错误
}
- 用
Set而非SetNX+Expire组合,保证原子性 - TTL 值应略大于业务单次有效时长(如登录态 30 分钟,设 35 分钟防时钟漂移)
- 若需“仅当不存在才设”,用
SetNX的变体Set第四个参数传redis.SetArgs{IfNotExists: true},但它仍支持Expiration字段
用 GET+DEL 做一次性消费时,注意 Lua 脚本才是原子解法
验证并删除令牌(比如校验 API 请求中的 token 后立即失效),不能分两步 GET 再 DEL —— 中间可能被其他协程重复消费。正确做法是用 Lua 脚本封装原子操作:
script := redis.NewScript(`
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("DEL", KEYS[1])
else
return 0
end
`)
result, err := script.Run(ctx, rdb, []string{"token:" + tokenID}, userID).Result()
- 脚本中用
GET校验值再DEL,避免误删其他用户的 token - 返回值为
1表示命中并删除成功,0表示未匹配或已不存在 - 不要依赖
GETDEL(Redis 6.2+ 才有),Go 客户端对老版本兼容性差,Lua 更通用
真正容易被忽略的点是:Redis 的“临时”完全依赖 TTL 精准控制,而不是配置层面的持久化开关。哪怕你把 save 和 aof 全关了,只要漏设一个 EX,那个 key 就会卡在内存里,直到 OOM 或运维手动清理。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











