Redis 字符串 SDS 存储大小
前言
突然对 Redis
里的 字符串存储空间感兴趣了,所以研究一下,分享在这里
更新: 2022-04-12 15:44:48 重新写了一下博客,之前写的貌似是错的 :(
RedisObject
redis 是一个 key-value
数据库, 无论是 key, 还是 value, redis 都使用 redisObject
来包裹
结构如下
struct RedisObject {
int4 type; // 4bits 表示对象的类型,包括5种基本类型
int4 encoding; // 4bits 表示值对象的内部编码
int24 lru; // 24bits 记录对象被命令访问的最后一次时间,和内存回收有很大关系
int32 refcount; // 4bytes = 32bits 记录被引用的次数
void *ptr; // 8bytes,64-bit system 指向真正内容的指针
}
源码位置是 redisObject
加起来就是 4 + 4 + 24 + 32 + 64 = 128 bit
,也就是 16 字节
SDS
redis 的 key 一定是一个 字符串,所以存储结构是 SDS
我们都知道 Redis
是使用 SDS
数据结构来存储字符串的,原因和好处不是本文关注的重点
数据结构 表述如下( Redis 3.0 版本的结构, 3.0之后变化很大,本文不关注)
3.0 sdshdr
struct sdshdr {
// 记录 buf 数组中已使用字节的数量
// 等于 SDS 所保存字符串的长度
unsigned int len;
// 记录 buf 数组中未使用字节的数量
unsigned int free;
// 字节数组,用于保存字符串
char buf[];
};
3.0 之后的版本,redis 会根据字符串长度的不同,选用不同的结构,如下
image.png
现在着重看一下 3.0 版本,这个版本的字符串结构用泛型来表达就是 RedisObject<Sds>
Key
int 长度为 4字节
初始化的时候,free=0
假设字符串长度为n
, 那么 sds
长度为 4+4+n+1
= n+9
1
是因为有个\0
所以对于 redis里的 key-value
来说,key 是 sds,那么长度就是 n+9
再加上外面包裹的 redisObject 的 16字节,所以 key
的长度是 n+25
字节
比如
set a b
那么 a
占了 26字节
Value
value
和 key 的差别在于,value 可以变化,可以 append
初始化的时候,长度和 key
是一样的
value修改 的时候
当第一次追加append
的时候,
如果新的大小 new=old+append
小于1MB
的时候, 扩容的时候就 翻倍, new=new*2
也就是说,假设原本长度为5, 扩容后变成15,那么扩容后 总长度为30,free
变成了15
如果新的大小new
大于1MB(new>1M
), 那么总长度是new=new+1M
, free
就是 1MB
当再次追加append
的时候,
如果free
够用,那么就直接使用
如果不够用,还是按照上面的策略来
缩短的时候
缩短的时候,是一个惰性释放
会把多出来的空间记录到 free
里,如果下一次扩容了,说不定能用上
当然了,redis
也提供了一些api,可以真正的去释放这些空间
结论
字符串作为 key
长度是n+25
字符串作为 value
如果没有被改过,那么长度也是n+25
;
如果被修改过,那就复杂了