2. Redis 基础回顾:数据结构概览、常用命令、键空间设计原则
在深入缓存契约与版本校验之前,必须夯实 Redis 基础。本章将系统梳理 Redis 的核心数据结构、高频操作命令以及键空间设计的关键原则,为后续的契约校验实战建立坚实的知识底座。
2.1 核心数据结构概览
Redis 提供了 9 种以上数据结构,但日常缓存场景中最常用的是以下 5 种。理解它们的底层编码与适用场景,是设计高效缓存契约的前提。
| 数据结构 | 底层编码(主要) | 最大元素数 | 典型缓存场景 |
|---|---|---|---|
| String | int / embstr / raw | 512 MB(单 key) | 会话 Token、计数器、JSON 序列化对象 |
| Hash | ziplist / hashtable | 2³² - 1 个 field | 对象属性缓存(如用户信息)、短结构化数据 |
| List | quicklist | 2³² - 1 个元素 | 消息队列、时间线、最新 N 条记录 |
| Set | intset / hashtable | 2³² - 1 个成员 | 标签系统、去重集合、好友关系 |
| Sorted Set (ZSet) | ziplist / skiplist + hashtable | 2³² - 1 个成员 | 排行榜、延时队列、带权重的缓存排序 |
契约视角提示: 在缓存契约版本校验中,Hash 和 String 是最常用的载体。Hash 天然支持字段级版本标记,而 String 适合存储完整的版本化 JSON 载荷。
2.2 常用命令速查
以下命令是日常缓存操作与契约校验的基础。按功能分组列出,便于快速查阅。
2.2.1 通用命令
EXISTS key— 检查 key 是否存在DEL key [key ...]— 删除一个或多个 keyEXPIRE key seconds— 设置 key 的生存时间TTL key— 查看 key 剩余生存时间TYPE key— 返回 key 存储的数据结构类型
2.2.2 String 命令
SET key value [NX|XX] [EX seconds]— 设置值,支持条件写入与过期GET key— 获取值MSET key value [key value ...]— 批量设置MGET key [key ...]— 批量获取INCR key— 原子自增 1
2.2.3 Hash 命令
HSET key field value— 设置单个字段HGET key field— 获取单个字段HMSET key field value [field value ...]— 批量设置字段HGETALL key— 获取所有字段与值HEXISTS key field— 检查字段是否存在
2.2.4 其他常用命令
LPUSH / RPUSH— 向列表头部/尾部插入元素LRANGE key start stop— 获取列表指定范围元素SADD key member— 向集合添加成员SMEMBERS key— 获取集合所有成员ZADD key score member— 向有序集合添加成员ZRANGE key start stop [WITHSCORES]— 按排名获取有序集合元素
契约校验高频命令组合:
WATCH key + MULTI / EXEC 用于乐观锁版本校验;EVAL "script" numkeys key [key ...] [arg ...] 用于 Lua 原子化版本比对与更新。
2.3 键空间设计原则
键空间设计直接影响缓存命中率、可维护性与契约校验的复杂度。以下 5 条原则是业界最佳实践。
- 命名规范: 使用
业务域:对象类型:标识符[:子域]的分层命名法。例如user:profile:1001、order:detail:ORD20250301。避免无意义的前缀或纯数字 key。 - 控制 key 长度: key 本身占用内存,过长会浪费空间且降低查询效率。建议 key 总长度不超过 128 字节,但也要保证可读性。
- 避免热点 key: 单个 key 承载过高 QPS 会导致 Redis 实例 CPU 飙升。可通过 key 打散(如加随机后缀)或 本地缓存 缓解。
- 设置合理的 TTL: 所有缓存 key 原则上都应设置过期时间。TTL 应与数据变更频率匹配,避免“永久缓存”导致的数据一致性问题。
- 版本字段预留: 在契约校验场景中,每个缓存对象应预留版本字段(如
_version或_etag),便于后续实现乐观锁或版本比对。
避坑提醒: 不要将版本号直接拼入 key 名称(如
user:1001:v2),这会导致缓存击穿时大量 key 同时失效。正确的做法是将版本号作为 Hash 的 field 或 String 值的一部分,通过原子操作更新。
2.4 键空间设计对比:好设计 vs 坏设计
| 维度 | 坏设计 | 好设计 |
|---|---|---|
| 命名 | u1001、order_20250301 |
user:info:1001、order:detail:20250301 |
| 长度 | user_profile_cache_for_user_id_1001_in_system_a |
user:profile:1001 |
| 版本处理 | user:1001:v2(key 内嵌版本) |
user:1001(Hash 内 field _version) |
| TTL 策略 | 所有 key 统一 3600 秒 | 按数据热度分层:热数据 300 秒,温数据 1800 秒 |
| 热点处理 | 单 key 承载所有请求 | key 打散 + 本地缓存兜底 |
2.5 数据结构选择与契约校验的关系
下图展示了不同数据结构在契约版本校验中的典型定位,帮助你在设计阶段快速做出选择。
2.6 实战:键空间设计示例
假设我们要为电商系统的商品详情页设计缓存,结合契约版本校验,推荐如下键空间方案:
# 商品基本信息(Hash 结构,字段级版本)
product:basic:1001
field: name -> "Redis 实战"
field: price -> "59.00"
field: _version -> "2025030101"
# 商品详情 JSON(String 结构,整体版本)
product:detail:1001
value: {"title":"Redis 实战","author":"张三","_version":"2025030101"}
# 商品排行榜(Sorted Set,版本号作为 score)
product:ranking:category:books
member: 1001 score: 2025030101
member: 1002 score: 2025030102
设计要点: 每个缓存对象都显式包含
_version 字段,版本号使用 yyyyMMddHHmm 格式的时间戳或单调递增的序列号。这样在契约校验时,只需比对版本号即可判断缓存是否过期,无需反序列化整个对象。