Redis Key 和 Value 的设计原则有哪些?

#中间件#面试八股

Redis Key 和 Value 的设计原则有哪些?

结论:Key 是"数据的地图",Value 是"数据的体积"。设计原则可归为三句话:Key 要有层次、可读、长度可控;Value 要小、要能局部更新、要能安全过期;两者都要为删除、迁移、排查留出余地。绝大多数线上事故不是命令用错,而是 key 设计让大 key、热 key、扫描全库变成了必然。

一、Key 的命名规范

原则反例正例说明
冒号分层user1001nameapp:user:1001:name便于 SCAN 按前缀巡检、按业务清理
带业务/环境前缀order:1trade:prod:order:1多业务共用一个实例时不串号
控制长度一长串 JSON 当 key哈希或 ID 短标识key 本身也占内存,且出现在每条命令里
避免动态拼接歧义user:1:2user:1:addr:2分层字段要能唯一还原语义
统一大小写与分隔符User:1001 / user-1001全小写 + 冒号减少人工排查成本
版本化user:1001user:v2:1001结构变更时可灰度、可回滚

二、Value 的设计约束

Value 变大 → 单次命令耗时↑ → 主线程阻塞 → 所有请求排队
          → 网络包变大 → 超时重试 → 雪崩
          → 删除/淘汰变慢 → 内存抖动
          → 迁移 slot / 主从同步变慢 → 故障恢复时间变长

因此 Value 侧的原则是:

  • 单 value 控制在 10 KB 以内,集合类元素数控制在几千以内(经验阈值,按业务实测调整);
  • 能局部更新就不要整体覆盖:对象用 Hash,避免每次改一个字段就重写整个 JSON;
  • 必须设置 TTL,且 TTL 加随机抖动,避免同一时刻集中过期;
  • 序列化选紧凑格式:JSON 可读但膨胀,Protobuf/MessagePack 更省,但要评估可读性与兼容成本;
  • 不要存二进制大文件:图片、视频放对象存储,Redis 只存 URL。

三、可落地的模板

{业务}:{环境}:{对象}:{ID}:{属性}
trade:prod:order:20261103001:detail      Hash,订单快照
trade:prod:user:1001:cart                Hash,购物车
auth:prod:sms:13800000000:code           String,验证码,TTL 300s
rank:prod:game:week:2026W45              ZSet,周榜
lock:prod:order:20261103001              String,SET NX PX
// 统一的 key 构造器 + 统一 TTL,避免各处手写字符串
public final class CacheKeys {
    private static final String PREFIX = "trade:prod:";

    public static String orderDetail(long orderId) {
        return PREFIX + "order:" + orderId + ":detail";
    }

    public static Duration orderTtl() {
        // 基础 30 分钟 + 0~5 分钟抖动,打散过期时间
        return Duration.ofMinutes(30 + ThreadLocalRandom.current().nextInt(5));
    }
}
# 巡检:按前缀抽样,而不是 KEYS *
redis-cli --scan --pattern 'trade:prod:order:*:detail' --count 1000 | head -20
# 看单个 key 的真实内存占用
redis-cli MEMORY USAGE trade:prod:order:20261103001:detail SAMPLES 0

四、常见追问

  • 问:key 太长会有什么问题?答:内存占用随 key 数量线性增长(每条命令与每个 dictEntry 都带 key),且日志、监控、慢查询里可读性差;一般建议控制在 100 字节内。
  • 问:能不能用中文或特殊字符做 key?答:可以,Redis 的 key 是二进制安全的,但排查、URL 编码、客户端工具兼容都会变麻烦,不建议。
  • 问:没有设置 TTL 的 key 有什么风险?答:内存只增不减,最终触发淘汰把有用数据挤掉;应通过巡检脚本定期找出 TTL == -1 的 key 并治理。
  • 问:Hash 字段多了要不要拆?答:单 Hash 超过几千字段就该考虑按维度拆(如按日期、按业务线),否则 HGETALL、过期、迁移都会变慢。
  • 问:Value 用 JSON 还是 Protobuf?答:读多写少、需要人工排查用 JSON;高 QPS、体积敏感用 Protobuf,但要固定 schema 并处理版本兼容。
  • 问:多业务共用一个 Redis 实例怎么隔离?答:用不同的 key 前缀区分,必要时分 db(Cluster 不支持多 db,只能靠前缀)或直接拆实例;前缀也是配额与巡检的依据。

小结

  • Key 解决"找得到、管得住",Value 解决"传得快、删得掉"。
  • 三条硬约束:单 value 小于 10 KB、集合元素数千以内、所有 key 必须有 TTL。
  • 设计时就把"怎么删、怎么迁、怎么排查"写进命名与结构里,比事后治理便宜得多。
笔记加载中…