Redis 专项测试点(剔除基础CRUD业务功能,聚焦线上故障、资损、数据错乱高频场景)
基础功能
1、缓存数据存储逻辑的合理性。缓存数据写入的正确性以及缓存的写入数据格式是否合理。
key:
一般使用业务名或数据库名作为前缀,以冒号(:)分隔来构造 key 名,不使用含义不清的 key 或特别长的 key;
命名中只能出现小写字母、数字、点(.)和冒号(😃。不要包含特殊字符,如下划线、空格、换行、单双引号以及其他转义字符;
value:
禁止超过 10KB 的 String 类型的大 key,防止网卡流量、慢查询。
非 String 类型的大 key,不要使用 del 删除,要使用 hscan、sscan、zscan 方式渐进删除。
2、缓存读取逻辑的合理性。有缓存要优先读缓存,无缓存查询数据库,并回写缓存。
校验数据在缓存和 DB 中都存在时,系统功能是否正常;
校验数据在 DB 存在,但缓存中不存在时,系统功能是否正常;
校验数据在缓存和 DB 中都不存在时,系统功能是否正常;
验证 DB 返回的数据异常时,没有去缓存;
**3、缓存更新逻辑的合理性。**什么情况下要更新缓存,以及缓存失效后是否会更新缓存内容。
缓存的更新策略:
1.先更新数据库,再更新缓存;
2.先更新缓存,再更新数据库;
3.先淘汰缓存,再更新数据库;
4.先更新数据库,再淘汰缓存。(推荐)
**4、缓存时间设置的合理性。**缓存时间设置太短,会导致频繁访问数据库;时间设置太长,一方面会占用过多内存,造成资源浪费;另一方面会造成用户访问到的一直是老数据。因此要根据业务数据的实际更新频次,设置合理的过期时间。
一、缓存和db一致性专项(资损/用户数据串号核心)
- 数据更新策略
- 先更新数据库再更新redis
- 如果在更新完数据库后,更新 Redis 缓存时出现故障(比如网络问题、Redis 服务宕机等),会导致 Redis 缓存数据和数据库不一致,后续读取缓存就可能获取到旧数据。
- 先更新redis再更新数据库
- 同样存在更新 Redis 后更新数据库失败导致的不一致风险,比如数据库更新时发生约束冲突等异常,使得数据不一致。
- 先删除缓存再更新数据库
- 删除 Redis 缓存 key
- 执行 SQL 更新 DB
问题:并发读写会出现脏数据
并发场景: - 线程A:删缓存
- 线程B:查询数据,缓存失效,读旧DB数据写入缓存
- 线程A:更新DB完成
结果:缓存存了旧数据,长期不一致,直到缓存过期。
先更新数据库再删除缓存- 执行 SQL 更新 DB
- 删除 Redis 缓存 key
理论脏数据窗口极小
并发读写: - 线程B:查询,缓存命中,拿到旧值(短暂)
- 线程A:更新DB
- 线程A:删除缓存
下一次查询会重新加载新数据。
只有一种极端脏数据场景:
查询刚好发生在「DB更新完成、缓存删除前」,只会产生极短时间脏数据,下次访问自动修复。
- 合理的缓存失效策略
- 根据业务数据的变更频率等因素,为不同类型的缓存数据设置合适的固定失效时间,比如对于频繁更新的数据设置较短的失效时间(如几分钟),而相对稳定的数据设置较长的失效时间(如数小时甚至一天)。
- 使用事务机制(侵入性强,并发性能不高)
- 分布式事务如seata,当 MySQL 和 Redis 在分布式环境下协同工作(比如跨多个服务、不同数据库实例等情况),可以采用分布式事务框架(如 Seata)来协调 MySQL 和 Redis 之间的操作,保证整个操作流程的一致性。
- 进阶优化
- 定期对 Redis 缓存和 MySQL 数据库的数据进行对比校验(可以通过数据对账等方式),一旦发现不一致的情况,根据预先设定的规则进行数据补偿操作,使两者恢复一致。例如,以数据库的数据为准,将不一致的缓存数据进行修正或者重新加载。
- 更新db后缓存删除失败兜底:重试删除(本地重试 + 延迟消息二次删除)、消息队列异步延迟删缓存(推荐)
- 极致强一致:业务代码只更新数据库,不操作缓存,基于 binlog 异步删缓存(Canal),适合高并发、高一致性场景
- 缓存延时双删(兼顾极致严谨),延迟 N 毫秒(根据业务查询耗时)再次删除缓存,作用:覆盖更新期间并发读写入旧缓存的极端场景,进一步降低脏数据窗口。
二、缓存穿透、击穿、雪崩三大经典风险
- 缓存穿透
大量不存在的Key(非法商品ID、无效用户)绕过缓存直查DB,压垮数据库;校验空值缓存、布隆过滤器拦截逻辑。 - 缓存击穿
热点Key过期瞬间海量请求打DB;校验互斥锁、永不过期、逻辑过期方案是否生效。 - 缓存雪崩
大量Key集中同时过期;校验过期时间随机打散、分层过期、集群分片隔离。
三、并发安全与共享对象污染(对应你短信/Go协程数据错乱问题)
- 共享可变对象并发读写
缓存Value为Map/结构体,取出后原地修改,多线程/协程共用同一份内存对象,参数交叉污染;校验是否强制深拷贝副本。 - 无锁并发更新热点Key
库存、余额、优惠券计数并发自增/自减,无分布式锁/乐观锁导致超卖、多发补贴; - Redis事务/管道并发冲突
multi事务执行中途失败、部分命令执行成功,数据不一致; - Lua脚本原子性校验
复杂扣减逻辑用Lua,校验脚本执行失败、超时、中断时数据不会错乱。
四、过期、淘汰、内存满边界场景
- TTL过期失效
业务配置缓存过期后,缺失兜底查DB逻辑,业务取空值造成计算错误; - 内存淘汰策略触发
Redis内存打满,触发LRU/LFU淘汰热点业务Key,大量请求降级查库;校验淘汰后业务容错; - 永久缓存无更新机制
静态模板、活动配置永久不过期,后台更新配置后缓存不刷新,长期使用旧规则。
五、分布式锁专项(高并发资损高发)
- 锁过期时间小于业务执行时长,锁提前释放,并发穿透;
- 锁不可重入,同一线程重复加锁死锁阻塞;
- 锁误删除:A的锁被B的del命令删掉;校验唯一标识(UUID)防误删;
- 集群锁同步延迟:主节点加锁后宕机,从节点未同步锁数据,新主可重复加锁;
- 锁自动续期逻辑:长任务看门狗续期中断,锁提前失效。
六、Redis高可用集群故障场景
- 主从切换、节点宕机
主库宕机切换从库,数据短暂缺失、同步延迟产生脏读; - 分片集群扩容/缩容、槽位迁移
Key迁移过程中读写丢失、读取空数据; - 网络分区(脑裂)
客户端与主节点断开,主从各自接受写入,数据分裂冲突; - 读写分离延迟
读从库读到滞后旧数据,并发业务计算出错。
七、网络、超时、异常链路测试
1. Redis连接超时、断连、端口不可达,需要有降级策略
校验降级逻辑:缓存异常是否自动查询DB,不直接报错/使用空脏数据;
2. 命令执行超时、管道批量命令阻塞
大批量mget/mset超大key阻塞线程,业务超时;
3. 连接池耗尽
未释放连接、连接池配置过小,大量请求阻塞等待连接;
4. 序列化/反序列化异常
对象嵌套、特殊字符、空值、日期类型序列化失败,缓存读取数据残缺。
八、大Key、热Key性能与数据风险
- 大Key风险
超大字符串、超大Hash/List,读写阻塞Redis,命令超时;校验拆分、裁剪逻辑; - 热Key热点访问
单个商品库存、活动模板被并发打爆,CPU打满、命令排队;校验本地二级缓存、分片隔离、缓存预热机制; - 批量操作边界
hgetall、lrange全量拉取海量数据,内存溢出、接口超时。
九、数据持久化与丢失风险
- RDB/AOF持久化配置故障
宕机重启丢失一段时间写入数据,缓存与DB不一致; - AOF刷盘策略
everysec/always切换,极端断电丢失数据,业务是否可自动补偿刷新缓存; - 持久化文件损坏,Redis启动失败,缓存全失效。
十、原子计数、限流器、计数器场景专项
- incr/decr并发扣减:无兜底校验导致库存负数、发放超额权益;
- 分布式限流计数器:限流窗口跨边界、过期重置逻辑错误,限流失效;
- 令牌桶/漏桶实现异常:流量突增无拦截,超量下单。
十一、特殊业务场景:本地缓存 + Redis 二级缓存
- 本地缓存脏数据,Redis已更新但本地未刷新,多实例数据不一致;
- 本地缓存共享可变对象,并发修改参数串用户;
- Redis缓存失效后,大量请求同时加载本地缓存产生并发重复计算。
十二、运维边界场景
- Key清空、flushdb/flushall、批量删除热点Key;
- 数据备份恢复,旧缓存覆盖最新业务数据;
- 权限管控:未做密码校验、高危命令开放,恶意清空缓存;
- 监控告警缺失场景:缓存命中率过低、大Key、连接池满无告警。
分类精简汇总(方便测试用例分组)
- !!!缓存双写一致性:更新DB+缓存并发脏读
- !!!缓存三大问题:穿透、击穿、雪崩
- !!!并发安全:共享可变对象污染、无锁并发扣减、Lua事务
- !!!分布式锁全场景风险(资损核心)
- 过期淘汰、内存打满边界
- 集群高可用:主从切换、槽迁移、脑裂
- 网络异常、连接池、超时降级逻辑
- !!!大Key、热Key性能阻塞
- 持久化宕机数据丢失
- 二级缓存(本地缓存+Redis)数据隔离
- 分布式计数器、限流组件异常
- 运维高危操作:清空、恢复、批量删Key