Redis 中 Key 的层级格式与命名规范
1. 什么是 Key 层级格式
Section titled “1. 什么是 Key 层级格式”Redis 的 Key 层级格式是一种人工约定的命名规范,并非 Redis 内置的技术特性。通过 : 等特殊字符分割不同层级,帮助开发者清晰组织和管理 Key。
层级格式示意:
user : 1001 : profile │ │ │业务模块 对象ID 子资源命名公式: 项目名:业务模块:对象类型:ID:子资源
# 用户系统user:1001:profile # 用户 1001 的基本信息user:1001:orders # 用户 1001 的订单列表user:1001:token # 用户 1001 的登录 Token
# 商品系统product:789:info # 商品 789 的元数据product:789:stock # 商品 789 的库存
# 多项目隔离(微服务场景)mall:user:1001:profile # mall 项目的用户信息pay:user:1001:balance # pay 项目的用户余额(前缀隔离,互不干扰)2. 核心价值
Section titled “2. 核心价值”| 价值 | 说明 |
|---|---|
| 可读性 | 一眼看出 Key 的归属业务、对象类型和用途 |
| 防冲突 | 不同业务/服务使用不同前缀,天然隔离命名空间 |
| 便于管理 | 配合 SCAN MATCH 可批量查找/清理某类 Key |
| 工具友好 | Redis 管理工具(如 RedisInsight)会按 : 自动分组展示,形成树形结构 |
3. 常用命名规范
Section titled “3. 常用命名规范”3.1. 分隔符选择
Section titled “3.1. 分隔符选择”| 分隔符 | 推荐度 | 说明 |
|---|---|---|
: | ✅ 强烈推荐 | 社区惯例,管理工具原生支持分组 |
_ | ⚠️ 可用 | 与 : 混用时容易混乱 |
/ | ❌ 不推荐 | 与路径语义冲突,易混淆 |
. | ❌ 不推荐 | 与域名/属性访问语义冲突 |
3.2. Key 长度建议
Section titled “3.2. Key 长度建议”| 建议 | 说明 |
|---|---|
| 控制在 44 字节以内 | Redis 对 ≤44 字节的 String key 使用 embstr 编码,内存更紧凑 |
| 避免超过 128 字节 | 过长的 Key 占用内存多,且每次操作都要传输完整 Key |
| 缩写模块名 | usr 代替 user,prd 代替 product(大规模 Key 时节省内存显著) |
| 避免动态时间戳拼接 | log:20260311:09:30:xx 这类 Key 难以管理,改用 ZSet score 存时间 |
3.3. Key 命名禁忌
Section titled “3.3. Key 命名禁忌”# ❌ 无前缀,无法区分业务归属SET name "Alice"SET token "abc123"
# ❌ 过深层级,可读性差SET user:1001:order:2024:03:detail:shipping:address "..."
# ❌ 大小写混用,容易拼错SET User:1001:Profile "..."SET user:1001:profile "..." # 与上面是两个不同 Key!
# ✅ 规范命名SET user:1001:profile "..."SET order:2024031001:detail "..."4. String vs Hash 存储多字段
Section titled “4. String vs Hash 存储多字段”对同一实体的多个属性,应优先用 Hash 而非多个层级 Key:
# ❌ 劣质方案:每个字段独立一个 KeySET user:1001:name "Alice"SET user:1001:age "25"SET user:1001:email "alice@example.com"# 问题:3 个 Key,3 次网络请求,内存开销大
# ✅ 优质方案:Hash 聚合同一对象的字段HSET user:1001 name "Alice" age "25" email "alice@example.com"# 优点:1 个 Key,1 次 HGETALL,内存更紧凑5. SpringBoot 中统一管理 Key 前缀
Section titled “5. SpringBoot 中统一管理 Key 前缀”手动拼接 Key 容易出错,推荐封装常量或工具类统一管理:
5.1. Key 常量类
Section titled “5.1. Key 常量类”public interface RedisKeys {
// 用户模块 String USER_PROFILE = "user:%d:profile"; // %d = userId String USER_TOKEN = "user:%d:token"; String USER_CART = "user:%d:cart";
// 商品模块 String PRODUCT_INFO = "product:%d:info"; // %d = productId String PRODUCT_STOCK = "product:%d:stock";
// 验证码 String VERIFY_CODE = "verify:code:%s"; // %s = phone
static String userProfile(long userId) { return String.format(USER_PROFILE, userId); }
static String userToken(long userId) { return String.format(USER_TOKEN, userId); }
static String productInfo(long productId) { return String.format(PRODUCT_INFO, productId); }
static String verifyCode(String phone) { return String.format(VERIFY_CODE, phone); }}// 使用:清晰、无拼写错误String key = RedisKeys.userProfile(1001L); // → "user:1001:profile"redisTemplate.opsForValue().set(key, json, 1, TimeUnit.HOURS);
String codeKey = RedisKeys.verifyCode("13800138000"); // → "verify:code:13800138000"5.2. Redisson Namespace(自动添加前缀)
Section titled “5.2. Redisson Namespace(自动添加前缀)”@Beanpublic RedissonClient redissonClient() { Config config = new Config(); config.useSingleServer() .setAddress("redis://localhost:6379") .setPassword("123456"); // 全局 Key 前缀:所有操作的 Key 自动加上 "mall:" 前缀 config.setNamespacePrefix("mall:"); return Redisson.create(config);}
// 业务代码中写 "user:1001",实际存储的 Key 是 "mall:user:1001"6. SCAN 按前缀批量操作
Section titled “6. SCAN 按前缀批量操作”# 分批次扫描(生产安全,不阻塞)SCAN 0 MATCH user:*:token COUNT 100
# 对应 SpringBootSet<String> keys = new HashSet<>();ScanOptions options = ScanOptions.scanOptions() .match("user:*:token") .count(100) .build();
try (Cursor<String> cursor = redisTemplate.scan(options)) { cursor.forEachRemaining(keys::add);}7. 命名规范速查
Section titled “7. 命名规范速查”✅ 推荐写法: {项目}:{模块}:{id}:{子资源} 全小写,: 分隔,层级 2~4 级
示例: user:1001:profile order:20260310001:status verify:code:13800138000 mall:product:789:stock
❌ 避免写法: 无前缀:name / token / data 大小写混用:User:1001 / USER_TOKEN 过深层级:a:b:c:d:e:f:g 含时间戳的动态深层级:log:2026:03:11:09:30:detail