真实面经题目 · 原创解析
缓存的 key 是什么?
缓存的 key 不是随手拼接的字符串,而是后端系统把业务对象、查询条件、租户环境、版本语义和一致性边界映射到缓存空间的唯一标识。一个好的缓存 key 需要同时解决可定位、可隔离、可失效、可观测、可扩展和可治理的问题,否则很容易出现串数据、删不准、热点集中、基数爆炸和线上排查困难。
真实面经题目 · 原创解析
缓存的 key 不是随手拼接的字符串,而是后端系统把业务对象、查询条件、租户环境、版本语义和一致性边界映射到缓存空间的唯一标识。一个好的缓存 key 需要同时解决可定位、可隔离、可失效、可观测、可扩展和可治理的问题,否则很容易出现串数据、删不准、热点集中、基数爆炸和线上排查困难。
面试中我会先说明:缓存的 key 是访问缓存数据的唯一业务标识,它决定了同一份数据如何被读、写、失效和监控。设计时不能只回答用用户 id 或商品 id 拼一下,而要从业务身份出发,把 namespace、环境、租户、业务对象、查询维度、版本号和粒度边界都表达清楚。例如用户详情可以抽象成业务域加对象类型加租户加用户 id 加版本,查询类缓存则要把会影响结果的参数做规范化排序和编码,避免同义参数生成多个 key。然后要说明风险控制:key 粒度太粗会互相污染,太细会导致基数过大;热点 key 要识别并做拆分、预热或本地缓存;失效时要保证 key 可枚举、可推导或有索引辅助;数据结构变化时通过版本号平滑切换;多环境和多租户必须隔离。最后补充可观测性,key 应该有统一前缀、指标维度和排查规则,既便于定位命中率、容量和热点,也便于灰度、回滚和批量清理。
缓存 key 首先表达的是这份缓存代表哪一个业务事实。用户详情、订单状态、商品库存、搜索结果的身份完全不同,不能只看技术字段,而要确认业务上什么变化会让结果不同。实体类 key 通常围绕主键或稳定业务唯一号,查询类 key 则围绕查询条件集合。只有业务身份定义准确,缓存命中才不会把 A 用户的数据返回给 B 用户,也不会把旧条件下的结果复用到新条件。
好的 key 命名应包含清晰的层次,例如系统域、模块、对象类型、租户、环境、业务 id、版本等。这样做的价值不是好看,而是让人和工具都能快速判断 key 属于谁、能不能删、影响范围多大。命名维度应稳定、短而明确,避免把无意义随机串放在主干位置,也避免不同团队各自创造前缀,最终导致运维和排障时无法聚合分析。
key 中应该放稳定且真正影响结果的字段,不应该放时间戳、请求流水号、随机数这类会破坏复用的字段,除非它们本身就是业务身份的一部分。对于查询参数,要做规范化处理,例如空值统一、默认值补齐、参数排序、大小写和编码规则统一。否则同一个查询可能生成多个 key,命中率下降,容量浪费,还会让缓存一致性问题更难定位。
版本号用于隔离数据结构或业务语义变化,租户和环境用于隔离不同数据边界。多租户系统如果 key 不带租户标识,很容易发生数据串读;测试、预发和生产如果共享同一 Redis 集群或命名空间,也必须通过环境维度隔离。版本号还可以支持平滑迁移,旧版本自然过期,新版本逐步承接流量,避免一次性大规模删除造成缓存击穿。
key 的粒度决定缓存复用率和失效成本。粒度太粗,例如把整个首页所有模块缓存成一个 key,命中率可能高,但任意小变化都要整体失效;粒度太细,例如每个轻微参数都生成独立 key,失效精准但数量膨胀、内存压力大。实际设计要根据访问频率、数据变化频率、组装成本和一致性要求权衡,常见做法是实体缓存细一些,聚合缓存按页面或场景适度分层。
有些 key 不只是数据缓存标识,还承担幂等控制或防重复处理的语义,例如请求幂等 key、分布式锁 key、去重 key。此时 key 必须和幂等边界一致:同一业务操作应命中同一个 key,不同业务操作不能误用同一个 key。幂等 key 还要考虑过期时间、状态值、失败重试和并发竞争,否则可能出现重复扣款、重复提交或误判请求已处理。
key 的数量规模必须可预估。用户 id、订单 id 这类高基数字段可以使用,但要配合 TTL、容量评估和淘汰策略;自由文本搜索、复杂筛选条件、组合参数如果直接进入 key,可能产生不可控的 key 数量。设计时要判断是否需要参数白名单、查询归一化、结果分桶、只缓存热门查询,或者对低频请求不缓存,避免缓存层被冷数据填满。
热点 key 是高并发系统中最常见的缓存风险之一。单个商品、活动配置、榜单或全局开关可能被大量请求集中访问,即使命中缓存,也会压垮单分片或网络链路。设计 key 时要考虑是否存在热点读、热点写和大 value,必要时使用本地缓存、多副本 key、随机过期、分片聚合、预热和限流等手段,把压力从单点打散。
缓存 key 必须能被准确失效。写数据库后是删除缓存、更新缓存,还是通过消息异步失效,取决于一致性要求和失败处理能力。key 如果无法根据业务 id 推导出来,或者查询缓存缺乏反向索引,数据变更时就很难清理相关缓存。面试中要强调 key 设计和失效策略是一体的:能读出来只是第一步,能在数据变化时正确清掉才是工程完整性。
线上缓存问题往往不是单个 key 错,而是命中率下降、内存异常、热点突增、过期风暴或序列化变化。统一 key 规范可以让监控按前缀统计容量、QPS、命中率、慢命令和热点分布。排查时也能通过前缀快速定位业务归属,通过版本判断数据结构,通过租户和环境缩小范围。没有可观测性的 key 设计,缓存系统越大越难治理。
不是。key 太长会增加内存和网络开销,但太短会损失可读性和隔离能力。工程上应在可诊断和可控成本之间平衡,保留必要的业务域、对象、租户、版本和身份字段,避免冗余描述。
先确定哪些条件真正影响结果,再对参数做规范化,例如排序、去空值、补默认值和统一编码。对于复杂条件,可以使用稳定摘要作为尾部标识,但前缀仍应保留业务含义,便于统计和排查。
版本号用于隔离不同的数据结构或业务语义。发布新逻辑时,新版本 key 可以自然承接新流量,旧版本 key 等待过期,避免旧数据被新代码误读,也降低批量删除带来的风险。
必须把租户标识放入稳定命名维度,并保证所有读写删除路径使用同一套 key 生成逻辑。不能依赖调用方口头约定,也不能只在 value 中区分租户,因为拿错 key 时已经发生了数据边界错误。
先通过监控识别热点前缀和具体 key,再按场景处理。读热点可以使用本地缓存、多副本 key、预热和限流;写热点要减少频繁重建,必要时用异步刷新或分片聚合降低单点压力。
因为数据变更后系统需要知道该删哪些缓存。如果 key 只能在查询请求中临时拼出来,写路径无法反推出相关 key,就会留下脏数据。实体缓存通常更容易推导,复杂查询缓存可能需要索引或按场景缩短 TTL。