ZREMRANGEBYSCORE 清不掉数据的根本原因是 score 时间戳单位未对齐,需统一使用秒或毫秒;它执行成员级清理而非 key 级删除,且 Redis 不自动清理逻辑过期的 ZSet 成员。

ZREMRANGEBYSCORE 清不掉数据?先确认时间戳单位对齐
根本不是命令写错了,而是 score 的时间精度没统一。ZSET 本身不感知“过期”,你得自己用时间戳当 score,而清理时必须和写入时单位一致:秒 or 毫秒。
查一条现有数据验证:ZRANGE key 0 0 WITHSCORES。如果返回的 score 是 10 位数(比如 1718256840),那就是秒;如果是 13 位(比如 1718256840123),就是毫秒。
- 写入用
int(time.time())→ 清理时也用int(time.time()) - 写入用
int(time.time() * 1000)→ 清理时也用int(time.time() * 1000) - 别混用,否则
ZREMRANGEBYSCORE key -inf 1718256840可能一个都删不掉
用 ZREMRANGEBYSCORE 删 ZSet 成员,不是删整个 key
EXPIRE 是 key 级操作,给整个 ZSET 设过期时间,等于说“这个排行榜整体到期就消失”——这和业务逻辑冲突。你要的是“人过期就下榜”,不是“榜单直接没了”。
ZREMRANGEBYSCORE 才是成员级清理,只删 score 落在指定范围内的元素,不影响其他活跃成员。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 命令格式固定:
ZREMRANGEBYSCORE key -inf (timestamp) -
(timestamp)表示开区间,即严格小于该时间戳的成员才会被删 - 下界别硬写
0,有人可能塞负分,用-inf更安全
一次别删太多,避免阻塞主线程
Redis 是单线程模型,ZREMRANGEBYSCORE 删除量过大(比如几万条)会卡住后续请求。尤其在高峰期,直接全量删风险很高。
- 先预估数量:
ZCOUNT key -inf (timestamp) - 超过 1000 条就分批删,例如:
ZREMRANGEBYSCORE key -inf (timestamp) LIMIT 0 1000 -
LIMIT参数仅 Redis 7.0+ 支持;旧版本只能靠客户端循环调用,每次删完检查ZCOUNT剩余量 - 建议加个延迟或放到后台任务里跑,别在用户请求链路里同步执行
别指望 Redis 自动帮你清 ZSet 过期成员
Redis 的惰性删除和定期删除机制,只管 key 是否过期,不管 ZSET 里某个 member 的 score 是不是“逻辑过期”。哪怕你把 score 设成时间戳,Redis 也不会主动扫描并删掉 score 小于当前时间的成员。
这事必须你自己做——定时任务、后台 job 或写入时顺手清理,没有捷径。最容易被忽略的点是:以为设了 EXPIRE 就万事大吉,结果 ZSET 越攒越厚,内存只增不减。

















