You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redis缓存key偶发未被删除的常见诱因及代码问题排查

缓存残留旧数据的典型诱因

  • 生产环境Redis服务默认禁用KEYS命令:为避免大量key匹配阻塞单线程的Redis,绝大多数云Redis服务、企业自建Redis都会禁用KEYS命令,函数执行时拿不到匹配的key列表,自然不会执行删除操作,而且如果没有错误捕获你感知不到这个失败。
  • 前缀匹配规则不一致:实际存储的缓存key和你传入的$prefix规则不匹配,比如多/少了分隔符、大小写差异、动态拼接了额外字段未同步到删除逻辑,导致KEYS搜索不到目标键。
  • 逻辑分支遗漏:如果文章操作的代码中,数据库写入抛出异常、或者走了其他分支提前返回,没有执行到删除缓存的逻辑,就会跳过删除步骤。
  • 主从同步延迟:如果使用Redis主从集群,删除指令发往主节点,但后续读请求落到还没同步到删除指令的从节点,会出现「缓存没删掉」的假象,实际是同步延迟导致的旧数据返回。
  • 连接中断:虽然整体网络正常,但短连接场景下,执行完KEYS获取键列表后、执行DEL之前Redis连接超时断开,会导致部分/全部key没删掉。

是否需要加数据库锁

不需要加数据库锁,会严重影响写入性能。你当前的更新逻辑「先删缓存、再更新数据库」本身就存在时序漏洞:如果并发场景下有读请求在删缓存后、数据库更新完成前读到旧数据,重新写回Redis,就会永久留存旧数据。
你只需要调整更新时序为:先更新数据库,再删除缓存,如果并发冲突概率较高,可以额外给缓存设置合理的过期时间兜底即可,不需要加锁。

提供的删除函数存在的错误

// 你的代码存在以下问题:
function articlesRedisDrop($prefix)
{
    $keys = $redis->keys($prefix."*"); // 问题1:$redis是全局变量,没有判断连接状态,连接失效时所有操作静默失败
                                       // 问题2:KEYS命令是阻塞操作,key数量多时会卡死整个Redis实例,生产环境禁用
                                       // 问题3:没有做参数校验,$prefix为空时会匹配并删除整个Redis实例的所有键,风险极高
    
    if(count($keys) > 0)
    {
        foreach($keys as $key)
        {
            $redis->del($key); // 问题4:循环逐个调用DEL会产生大量网络IO,应该直接批量传入所有键一次性删除
        }
    }
    // 问题5:没有任何异常捕获和返回值,删除失败时上层逻辑完全感知不到问题
}

修复建议

用非阻塞的SCAN命令替代KEYS,添加参数校验、错误处理和批量删除逻辑即可。

内容的提问来源于stack exchange,提问作者FrozenCoyote

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 14:24:01