压测时触发缓存雪崩,导致数据库被打挂,你会如何调整数据模型

解读

面试官想验证三件事:

  1. 能否快速定位“雪崩”根因——缓存大面积失效时间集中、查询穿透到 DB、连接池瞬间打满;
  2. 能否给出“数据模型层”可落地的改造方案,而不是只喊“加缓存、限流”这类运维口号;
  3. 是否具备国内互联网高并发场景下的工程权衡意识(成本、灰度、兼容、回滚)。
    因此回答必须围绕“数据模型”本身,兼顾缓存策略、DB 访问模式与压测场景,给出可量化、可验证的改进清单。

知识点

  1. 缓存雪崩:大量 key 同时过期或缓存实例宕机,请求直穿 DB,QPS 瞬间超过 DB 最大连接数与 CPU 承载。
  2. 数据模型层优化手段:
    • 冷热分级:把热数据拆成“频繁读但极少改”的轻量字段,与“读写都频繁”的业务字段物理隔离;
    • 冗余与宽表:对高并发读场景做适度字段冗余,减少 join;
    • 分片键重设计:让同一缓存 key 对应的数据落在同一分片,避免跨片查询放大;
    • 过期时间散列化:在模型层给每条记录引入随机 TTL 偏移字段,写入时持久化到元数据表,缓存加载脚本读取该字段做随机过期;
    • 异步写+消息队列:把写操作先落地队列,再异步落库,降低峰值连接;
    • 二级缓存模型:本地 Caffeine + Redis,数据模型层提供版本号字段,支持本地缓存秒级失效;
    • 降级字段:在主体表增加“缓存降级标志”+“静态默认值”列,压测时可直接返回默认值,保护 DB。
  3. 国内常用组件:MySQL 8.0、Redis 6.x Cluster、ShardingSphere、RocketMQ、DTS 同步、Canal。
  4. 压测验证指标:缓存命中率、DB 连接数、95rt、错误率、CPU io wait、慢查询数。

答案

压测出现雪崩,说明“缓存失效集中度 > DB 最大安全并发度”。我会从“数据模型”角度做四步调整,并配合灰度压测验证。

第一步,冷热分离,重写表结构

  • 把用户维度的“状态 flag、分值、标签”等高热度只读字段拆成 profile_simple 表,主表只留更新频繁字段;
  • 在 profile_simple 表新增 ttl_offset tinyint 字段,写入时随机 0~900 秒,作为缓存过期散列依据;
  • 热数据表采用 MyISAM 或 TokuDB 压缩存储,减少内存占用,提高缓存命中率。

第二步,缓存 key 与分片键对齐,避免跨片热 key

  • 若原分片键是 user_id,缓存 key 也统一用 user_id,保证同一用户的数据与缓存落在同一 Redis 分片;
  • 对超高频 key(如活动配置)引入“分桶 key”模型:activity_config_{activityId}_{bucket},bucket=hash(activityId)%32,把集中过期打散到 32 个桶,每个桶过期时间再叠加 ttl_offset。

第三步,引入异步写与消息队列,削峰填谷

  • 在主体表新增“version”字段,每次更新 version+1,缓存层用 version 做 CAS,防止并发回写;
  • 写操作先落 RocketMQ,消费组异步批量落库,批量大小按“DB 最大安全 IOPS*0.6”反推,降低峰值连接;
  • 消息体里带上 ttl_offset,消费成功后刷新缓存并重新设置散列过期时间。

第四步,压测模型与降级字段

  • 在热数据表加“cache_downgrade_value”列,压测前预置默认值;
  • 当缓存 miss 且 DB 连接数>80% 时,服务层直接返回 cache_downgrade_value,不查库;
  • 通过 Chaos 脚本模拟 Redis 全挂,观察降级值是否保护 DB,目标:DB 连接数<60%、错误率<0.1%。

灰度验证

  • 用影子表+影子缓存做 1% 流量灰度,逐步上调到 30%,确认 95rt 下降 40%、缓存命中率>92%、DB 峰值连接下降 55% 后,再全量发布。

拓展思考

  1. 如果业务不允许异步写,如何同步写同时保证缓存与 DB 双写一致?
    答案方向:采用“延迟双删”+“binlog 订阅补偿”模型,数据模型层增加“last_cache_flush”时间戳字段,Canal 订阅 binlog 对比时间戳决定是否二次删缓存。

  2. 当雪崩由热点 key 而非集中过期引起,数据模型层还能做什么?
    答案方向:在模型层把热点 key 做“字段级拆分”,例如把商品库存拆成“总库存”和“分库库存”两行记录,缓存层面使用分片锁+本地缓存,减少单 key 冲击。

  3. 国内金融场景对一致性要求极高,如何兼顾雪崩防护与事务?
    答案方向:数据模型层引入“冻结额度”字段,缓存只放“冻结额度”快照,真正扣减走 DB 悲观锁,事务提交后再异步更新缓存,保证账务平衡。