Redis:多大的 key 算大?如何查找?如何拆分?
🏷️ Redis
多大的 key 算大 ?
关于 Redis 中多大的 key 算大,这个貌似没有统一的定义。下面是摘自几篇博客中的关于大 key 的定义:
定义一:[1]
- 单个简单的 key 存储的 value 很大;
Hash
,Set
,ZSet
,List
中存储过多的元素(以万为单位);- 一个集群存储了上亿的 key , key 本身过多也带来了更多的空间占用;
定义二:[2]
- value 是
String
类型时, size 超过 10KB ;- value 是
ZSet
、Hash
、List
、Set
等集合类型时,它的成员数量超过 1w 个。上述的定义并不绝对,主要是根据 value 的成员数量和字节数来确定,业务可以根据自己的场景也确定标准。
定义三:[3]
String
类型的 key 对应的 value 超过 10MB。List
、Set
、Hash
、ZSet
等集合类型,集合元素个数超过 5000 个。
定义四:[4]
- 合理的 key 中 value 的字节大小,推荐小于 10 KB;
可以看到每位作者的标准都不太一样,有的差别还比较大。
单个 String
key 有的定义是 > 10KB,有的是 > 10MB 。虽然差别比较大,但可以取一个中间的数量级 320KB 或者取个整 500KB 作为参考。
集合类型的元素数量倒是差别不算很大,基本上在万这个数量级上就认为是大 key 了。
如何查找?
我自己参加的项目大都使用的是云上的 Redis ,其管理后台都提供了类似的诊断、分析工具,甚至可以自动告警。不仅是大 key ,热 key 和慢查询的检测一般也都支持。
自建 Redis 服务器的就只能自己分析了,下面是两种常用的查找方法:
使用
BIGKEYS
命令shellredis-cli --bigkeys
使用这个命令的缺点就是它会阻塞 Redis ,生产环境慎用。
使用 redis-rdb-tools 工具扫描 rdb 快照文件
虽然实时性差一点,但不影响使用。
如何拆分?
对于大 key 问题,比较普遍的解决方法就是拆分:将过大的 key 拆分成合适大小的小 key 。
印象中之前看过一篇性能测试,说是 Redis 的集合中元素数量在 1500 左右的时候性能最高(印象中是这个数字,但是具体的文章没有找到),所以我编码的时候经常以 1500 为标准拆分集合。
至于如何拆分可以根据业务自己决定,类似于数据的分表,定义好合适的规则就可以了。总之目标就是尽量平均拆分,且每个 key 里的元素不会太多。
最常用的拆分方法就是将 key 的哈希值 mod 一个合适的数值(分片的数量):
(key.hashCode() & Integer.MAX_VALUE) % N
对于 String
类型的大 key ,比较常用的则是压缩。
比如,如果使用的是 JDK 默认的序列化(Serializable
)或者是 XML 格式的序列化,可以考虑改为使用 JSON 格式。 JSON 格式由于比较紧凑,一般占用的空间相对比较小。另外还可以基于序列化之后的结果进行压缩,比如 GZIP 或 Snappy ,再次减少 Redis 内存空间的占用。[5] 需要注意的是,这些都是通过消耗服务器的时间来减少 Redis 空间的占用,也就是时间换空间,所以需要结合实际的场景决定是否需要压缩。