腾讯云分布式缓存数据库支持 Redis、Valkey、Memcached 等多种存储引擎。本文档定义缓存实例中 Key 与 Value 的设计原则,帮助您在开发过程中规范数据模型设计,提升缓存性能和可维护性。
一、Key 设计原则
Key 命名需具有可读性及可管理性,不建议使用含义不清的 Key 以及特别长的 Key 名。
原则 | 说明 |
简洁性 | 保证语义的前提下,可以适当缩短 Key 的长度。当 Key 较多时,Key 占用的内存空间也不容忽视。 |
命名规则 | 以英文字母开头,命名中只能出现大小写字母、数字、竖线、下划线、英文点号( .)和英文半角冒号(:)。 |
语义分割 | 不同业务逻辑含义使用英文半角冒号( :)分割,同一业务逻辑含义段的单词之间使用英文半角点号(.)分割,用来表示一个完整的语义。 |
可读性 | Key 名称以 Key 所代表的 Value 类型结尾,以提高可读性。例如: user:basic.info:userid:string。 |
长度限制 | Key 名称过大也会占用一定的内存空间,建议控制在128字节以内。 |
禁止特殊字符 | 禁止使用 \\、*、?、{}、[]、()、空格、单双引号和转义字符等,否则可能导致 Key 无法检索或检索失败。 |
正确示例:
示例 | 说明 |
cx:cxdb:user:000110011 | 简洁、语义清晰,使用冒号分层。 |
user:basic.info:userid:string | 同一语义段使用点号分割,以 Value 类型结尾。 |
反面示例:
示例 | 问题 |
cx:cxdb:cxdb_user_info:000110011 | 表名中重复包含库名 "cxdb",冗余且增加 Key 长度。 |
set user 000110011 | Key 中包含空格,属于禁止使用的特殊字符。 |
二、Key 生命周期准则
建议使用 expire 设置过期时间,控制 Key 的生命周期。
# 写入 Key> set cx:cxdb:user:000110011 xiaoming# 设置 Key 一小时后过期> expire cx:cxdb:user:000110011 3600
如果条件允许可以打散过期时间,防止集中过期。
对于没有设置过期的数据,重点关注 idletime。在 idletime 非常大时进行清理。
当一个 Key 有1个月以上未被访问过,则可以认定为冷数据,并进行清理。
查看 Key 闲置时间示例:
> object idletime cx:cxdb:user:000110011(integer) 150039 # 表示该 Key 有 150039 秒未被访问过
说明:
如果条件允许,建议为过期时间增加随机偏移量(例如基础 TTL ± 随机秒数),避免大量 Key 在同一时刻集中过期导致缓存雪崩。
三、Value 设计原则
3.1 拒绝大 Key
大 Key 具体表现为缓存实例中的 Key 对应的 Value 很大,占用内存空间比较大,本质上是大 Value 问题。对于不同的数据结构类型,常见示例如下所示:
数据结构类型 | 大 Key 判定条件 | 问题说明 |
String | Value 值超过10MB。 | 数据值太大 |
Set | 成员数量超过10000个。 | 成员数量多 |
List | 成员数量超过10000个。 | 成员数量多 |
Hash | 成员数量超过1000个,且成员总 Value 值大小为1000MB。 | 成员总的体积过大 |
大 Key 很容易造成慢查询,阻塞其他的请求,同时也会对网卡造成负担。为防止产生大 Key,设计 Value 时建议参考如下准则:
准则 | 说明 |
控制 Value 大小 | String 类型控制在10KB以内;Hash、List、Set、Zset 元素个数不要超过5000。 |
避免直接删除大 Key | 若非必须,不要使用 del 删除大 Key。 |
渐进式删除 | 对于非字符串的大 Key,建议使用 hscan、sscan、zscan 渐进式删除。 |
关注过期自动删除 | 防止大 Key 过期时间自动删除问题。例如一个200万的 Zset 设置1小时过期,会触发 del 操作,造成阻塞。 |
3.2 合理选择数据类型
缓存实例提供了多种不同的数据结构类型,包括字符串、哈希表、列表、集合和有序集合等。选择合适的数据结构类型可以提升缓存性能和可靠性。
数据结构类型 | 适用场景 | 说明 |
字符串(String) | 简单的字符串数据,例如配置信息、计数器等 | 如果需要存储二进制数据,可以使用二进制安全字符串类型 |
哈希表(Hash) | 多个字段和值的数据,例如用户信息、商品信息等 | 可以节省内存空间,方便进行批量操作 |
列表(List) | 有序的元素集合,例如消息队列、任务列表等 | 支持在两端进行插入和删除操作 |
集合(Set) | 无序的元素集合,例如标签列表、好友列表等 | 支持并集、交集、差集等操作 |
有序集合(Sorted Set) | 有序的元素集合,例如排行榜、投票列表等 | 按照分值排序,支持范围查询 |
3.3 内存编码优化
合理控制和使用数据结构内存编码优化配置。例如 ziplist 是一种特殊的数据结构,可以将小型列表、哈希表和有序集合存储在一个连续的内存块中,从而节省内存空间。
场景 | 建议 |
数据量较小且需要频繁遍历 | 适合使用 ziplist,内存利用率更高 |
数据量较大且需要频繁插入、删除或查找 | 不建议使用 ziplist,应考虑使用其他数据结构代替 |
说明:
ziplist 没有索引,查找、插入或删除操作需要进行线性扫描,数据量较大时可能导致性能下降。应根据具体数据量和访问模式决定是否启用。
3.4 使用 Hash 代替多个 String
如果一个 Key 有多个属性,可以考虑使用 Hash 类型来代替 String 类型。Hash 是一种键值对存储数据结构,可以用于存储多个字段和值。使用 HSET 命令将多个字段和值存储在一个哈希表中,然后使用 HGET 命令获取指定字段的值。如果使用 String 类型来存储多个属性,则需要使用特定的分隔符将不同的属性值拼接成一个字符串,这样会使得操作复杂,并且可能会浪费内存空间。
反面示例: 使用多个 String 类型存储同一对象的属性,Key 数量膨胀且无法原子操作。
set user:1:name tomset user:1:age 19set user:1:favor football
Running Environment
Operating System: Ubuntu 24.04.3 LTS / x86_64
Runtime Version: GNU bash, version 5.2.21(1)-release (x86_64-pc-linux-gnu)
正确示例: 使用 Hash 类型将同一对象的多个属性聚合为一个 Key,减少 Key 数量并支持原子操作。
hmset user:1 name tom age 19 favor football