Redis过期Key需手动兜底清理,因惰性+定期删除机制可能导致内存滞留;应使用SCAN替代KEYS,批量TTL校验后DEL删除,并通过APScheduler定时执行,同时加强命名规范、日志统计与监控告警。

Redis中Key的过期机制本身不等于自动清理
Redis的EXPIRE或SET ... EX设置的是逻辑过期时间,但Key不会在到期瞬间被物理删除。Redis采用惰性删除(访问时检查)+ 定期抽样删除(后台周期性扫描),这意味着大量过期Key可能长期滞留,尤其在低访问量场景下内存持续增长。这不是bug,是设计权衡——但你得自己补上“兜底清理”。
用redis-py扫描并批量删除无用Key的实操要点
别用KEYS *——它会阻塞主线程,生产环境禁用。改用SCAN游标式遍历,配合模式匹配和条件过滤:
-
SCAN返回的Key需逐个调用TTL确认是否真过期(返回-2表示Key不存在,-1表示永不过期,非正数才可删) - 单次
SCAN默认只返回10个Key,建议显式设count=100减少往返次数,但别设太大(如10000),避免单次耗时过长 - 删除操作用
DEL而非UNLINK(后者异步,但redis-py旧版本可能不支持返回值解析) - 加
try/except捕获ConnectionError和ResponseError,避免一次失败中断整个清理流程
示例片段:
import redis
r = redis.Redis(host='localhost', port=6379, db=0)
cursor = 0
while True:
cursor, keys = r.scan(cursor, match='cache:*', count=100)
if keys:
ttl_list = r.ttl(*keys) # 批量查TTL,注意部分版本不支持多key
to_delete = [k for k, t in zip(keys, ttl_list) if t and t <= 0]
if to_delete:
r.delete(*to_delete)
if cursor == 0:
break
用APScheduler在Python进程内做定时触发
如果Redis清理逻辑已封装成函数(如clean_expired_cache()),直接挂到APScheduler的BackgroundScheduler即可,无需额外起服务:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
立即学习“Python免费学习笔记(深入)”;
- 选
IntervalTrigger(minutes=5)比CronTrigger更轻量,适合简单周期任务 - 务必调用
scheduler.start(),且主程序不能立即退出(例如加time.sleep()或用Event().wait()保持运行) - 避免在Web应用(如Flask/FastAPI)的请求线程里启调度器——会导致重复实例化,用单独进程或系统级cron更稳
关键配置行:scheduler.add_job(clean_expired_cache, 'interval', minutes=5)
真正要警惕的不是技术实现,而是误删和监控缺失
缓存Key命名没规范?match='cache:*'可能误伤业务Key;没记录清理日志?出问题时无法回溯。必须做两件事:
- 清理前用
SCAN先统计匹配Key总数和预估过期率,写入日志(例如“扫描到1248个cache:* Key,其中312个TTL≤0”) - 所有
DEL操作必须包裹在pipeline里,并启用transaction=False避免WATCH开销;同时对删除量设硬上限(如单次最多删500个),防突发全表误删
最常被跳过的一步:在Redis监控面板(如redis-cli info memory里的used_memory_peak)加告警,而不是等OOM才发觉清理失效。

















