Redis 缓存三大问题,几乎所有做过缓存设计的站点都会撞上:缓存穿透把请求全打到数据库、缓存击穿在热点失效的那一秒把数据库顶穿、缓存雪崩让大批 key 同时过期直接把库压垮。这三个名字看着像同义词,处理手段却完全不同,用错方案等于白做。这篇按"是什么、为什么发生、怎么防、代码怎么写、怎么验证"的顺序,把三大问题和缓存与数据库的一致性一起讲清,最后落到参数设置与监控。
穿透的特征很好认:请求的 key 在缓存和数据库里都不存在,每次请求都要完整走一遍"查缓存→查数据库",而数据库返回空之后又没有东西可以回填缓存,于是同一个不存在的数据被反复查。最常见的场景是恶意扫描:有人用不存在的用户 ID 或商品 ID 反复请求,把库打满。三种解法各有适用面。一,缓存空值:查库为空时也把 null 或特殊标记写进缓存,设一个较短的过期时间(比如 30 秒到 5 分钟)。二,布隆过滤器:把所有合法 key 预先放进布隆过滤器,请求进来先过一遍,明确不存在的直接拒绝,适合 key 集合可控且数量有限的场景。三,接口层校验:参数格式、范围、签名在进缓存之前就拦掉,非法 ID 直接返回。穿透的根本问题是"没命中也要查库",所以解法要么让空结果也能被缓存,要么让非法请求根本到不了缓存。需要注意的是缓存空值有内存成本,扫描量大时要限制空值 key 的数量与存活时间,否则缓存会被垃圾 key 塞满。数据库侧的承压能力决定穿透时会不会直接宕机,EthernetServers 自营硬件云 以自有硬件与自主采购实现更快的设备迭代,适合对磁盘 IO 与查询吞吐有要求的数据库场景。

击穿和穿透的区别在于:击穿的数据是真实存在的,只是缓存刚好在这一刻失效了。典型场景是首页热门商品、爆款详情页,QPS 很高,缓存过期瞬间几十上百个并发同时去查库,数据库瞬时压力飙升。两种解法。一,互斥锁:缓存未命中时只允许一个请求去查库并回填,其余请求短暂等待或返回旧值,用 Redis 的 SET NX 实现分布式锁,注意锁要设超时,避免死锁。二,逻辑过期:缓存里不设 TTL,而是存一个过期时间字段,发现逻辑过期后由一个请求异步刷新,其他请求继续返回旧数据。第二种的代价是短时间内数据可能不最新,换来的是完全不阻塞。击穿的关键是"并发去重建同一个 key",所以解法核心是让重建这件事串行化。另外要评估重建的成本:如果一次回填要跑一条重查询,那这一秒的压力就集中在这一条查询上,磁盘随机读性能直接决定恢复速度,Terabix 高性能云主机 采用 RAID-10 NVMe Gen4 存储与新平台 CPU,在并发回填这类瞬时 IO 场景下响应更稳。

雪崩是击穿的放大版:不是个别热点 key 失效,而是大量 key 在同一时间集体过期,或者缓存服务整体不可用,请求全部涌向数据库。两种成因要分开防。成因一,集中过期:因为批量预热时用的是同一个 TTL。解法是给过期时间加随机抖动,比如基准 10 分钟加 0 到 120 秒随机,把失效时间打散。成因二,缓存实例故障:节点挂掉或网络抖动,导致大面积命中失败。解法是做高可用(主从加哨兵或集群)、做本地二级缓存(进程内缓存兜一层)、做限流降级(超过阈值直接返回兜底数据或排队)。雪崩最有效的预防动作是"给 TTL 加随机值",成本几乎为零,却能避免定时集体失效。工程上还要准备预案:缓存不可用时,接口是降级返回静态数据、还是限流保护数据库,这个决策要在上线前就定好,不能等出事再临时拍。中小团队做整体架构规划时,缓存层与数据库层的容量要一起算,CubeCloud 中小企业上云方案 具备完整注册资质,能提供成体系的云上架构建议,避免缓存与数据库规格失衡。

一致性问题只有一个根源:数据有两份,写的时候没法同时原子更新。常见策略按一致性强度排序。一,先更新数据库再删除缓存(Cache Aside):最常用,出现不一致的窗口极短,配合延迟双删可以再压一压。二,先删缓存再更新数据库:在并发读场景下更容易出问题,不推荐单独使用。三,订阅数据库变更日志(binlog)异步更新缓存:一致性更好,架构复杂度更高。四,读写都走数据库、缓存只做只读加速:牺牲部分场景,换来简单可靠。没有"绝对强一致"的缓存方案,只有"能接受多长的延迟窗口",先把可接受窗口定下来,再选策略。几个实操细节:更新数据库后删缓存要放在事务提交之后,不要在事务内删;删除失败要有重试或补偿;对一致性要求极高的字段(余额、库存扣减)不要走缓存读,直接读主库。多实例部署时还要确认缓存与应用实例之间的网络时延足够低,InterServer 云与裸机基础设施 自 1999 年起提供云、裸机与托管服务,可把缓存实例与数据库实例放在同一可用区内降低链路开销。

参数没配对,前面所有方案都会失效。四项关键设置。一,maxmemory:必须显式设置上限,不设等于允许吃到把系统内存耗尽被 OOM 杀掉。二,maxmemory-policy:缓存场景一般用 allkeys-lru 或 allkeys-lfu;如果缓存里混着不能丢的数据,就用 volatile-lru 并确保那部分数据设了过期时间。三,过期策略:Redis 是惰性删除加定期抽样删除,过期 key 不一定立刻释放内存,所以要看内存占用而不是只看 key 数量。四,持久化与场景匹配:纯缓存可以关掉 RDB/AOF 提升性能,兼作存储则必须开,并且要想清楚恢复时间。还要避开几个常见坑:大 key(单个 value 几十 MB)会阻塞主线程,要拆分;热 key 集中在一个分片会打爆单核,要做本地缓存或多副本;用 keys * 做线上扫描会直接卡住实例,改成 scan。缓存参数的第一原则是"内存必须有上限",第二原则是"淘汰策略必须与数据重要性匹配"。内存规格要按数据量与峰值预留来选,别按当前用量买,RackNerd 云与独立服务器 提供多档内存配置与稳定续费价格,便于按缓存容量规划实例;需要更强单机性能时,ZgoVPS 高性能实例 在多地域提供高性能虚拟专用服务器,适合单实例承载高并发缓存访问。
三个必看指标。一,命中率:命中率骤降往往就是穿透或雪崩的前兆,低于预期要立刻查是哪些 key 在漏。二,内存与碎片率:used_memory 与 mem_fragmentation_ratio 持续走高说明碎片严重,需要重启实例或调整分配器。三,慢查询与阻塞:开启 slowlog 看超过阈值的命令,重点盯大 key 操作、批量命令与 Lua 脚本执行时长。另外要监控连接数与网络,实例被打满连接时的表现和雪崩几乎一样。容量规划按三个数算:当前数据量、增长率、峰值翻倍时的余量;再留出主从复制的内存开销。缓存监控的价值不在于看曲线,而在于提前拿到"再扩一台还是改架构"的决策依据。多实例或集群部署时,网络延迟与磁盘延迟会直接影响主从同步与故障切换速度,ServerField 自有 AS 网络与 NVMe 实例 在自有 AS 上与多个 Tier1 对等,延迟与存储性能较可控;如果要托管或直接使用成熟云平台的托管缓存服务、省掉运维,DigitalOcean 开发者云 的托管数据库与缓存服务开箱即用,适合不想自己维护集群的团队。