Redis容量估计
Redis容量估计
错误的理解:误以为序列化后的Size与存到redis后的Size差不多,但实际上,差距还是蛮大的。
实际工程中,可以直接使用这个工具快速判断可能的占用大小:Redis容量估计工具
错误的估计
现有任务1与任务2需要向redis写入数据:
任务1:
- 其一天的的数据个数有:293, 659, 385个(约3亿数据)
- 其序列化后的value的大小共有:50.14 GB
- 均到3亿数据上,大约每一个value大小为:180 字节
任务2:
- 其一天的数据个数有:231419688个(约2.3亿数据)
- 其序列化后的value的大小有:23.55GB
- 均到2.3亿数据上,平均每一个value大小为:107 字节
就认为总共的数据也就:23 + 50 GB,但是实际占用Redis集群空间:303 GB(2倍副本,实际存储150GB数据)
这和预估数据远远不符,因此使用Redis容量预估工具 http://www.redis.cn/redis_memory/ 重新进行估算:
预估的容量为89GB与49GB,和为138GB(与实际占用150GB差距不大)
原理探究
为什么我们23 + 50 GB的数据存入Redis变为了150GB?Redis都维护了怎样的结构?
Redis String的编码方式
由于我们只使用了redis的String存储结构(本质是byte[]
),因此这里只分析String。
String在redis内有三种编码方式(如下图所示)
int
编码:在保存 64 位有符号整数时embstr
编码:在保存的字符串小于 44 字节时raw
编码:大于 44 字节时(embstr与raw的区别仅在于SDS是否与元数据的指针紧挨)
Redis存储数据需要维护的结构
Redis存储数据,需要维护的数据有:(如下图所示)
dictEntry
结构:24字节,向上取整为32字节key
:存储键key,自己维护9字节的信息,因此大小为key+9,且大小向上取整 16/32/64/128/256/…字节redisObjet
:16字节- 元数据:存放LRU、LFU的关键信息:时间戳、频次
- 指针:指向具体结构,对于String就是一个SDS(简单动态字符串)
value
:存储对应value,由于存储String,也需要维护9字节信息,也是向上取整16/32/64/128/256/…字节bucket
个数信息:key的个数增多,redis需要rehash扩展Dict数组,每一个数组的元素是一个8字节指针,因此需要存储key的个数的幂次向上取整。(比如有2000个key,需要有2048个bucket,每个bucket需要8字节)
Redis容量预估计算公式
因此,可以得出Redis容量计算的推理公式:
1 | -- 此处 Pow(x) 表示对x求 最近的2的幂次且向上取整 |
我们可以自己估算一下,上一节提到的两个任务的大小:
对于任务1:
1 | Value = (32 + Pow(22 + 9) + Pow(180 + 9) + 16) * 300_000_000 + Pow(300_000_000) * 8 |
105094967296换算为97GB,这与Redis容量工具计算基本一致
对于任务2:
1 | Value = (32 + 32 + 128 + 16) * 230_000_000 + 2^28 * 8 |
49987483648字节换算为46GB,这也与Redis容量工具计算基本一致