五种常见数据对象
- 字符串对象
- 列表对象
- 哈希对象
- 集合对象
- 有序集合对象
Redis中每个对象都有一个RedisObject结构表示,该结构具体如下:
typedef struct redisObject {
// 对象的类型,字符串/列表/集合/哈希表
unsigned type:4;
// 未使用的两个位
unsigned notused:2; /* Not used */
// 编码的方式,Redis 为了节省空间,提供多种方式来保存一个数据
unsigned encoding:4;
// 当内存紧张,淘汰数据的时候用到
unsigned lru:22; /* lru time (relative to server.lruclock) */
// 引用计数
int refcount;
// 数据指针
void *ptr;
} robj;
字符串对象
字符串对象可以是int、raw、embstr
如果字符串对应保存的是一个整型数据,则编码方式设置为int
如果字符串对象保存的是一个字符串
- 长度大于39个字节,则使用SDS来保存当前字符串,并将对象编码格式设置为raw
- 长度小于39个字节,则将对象编码格式设置为embstr。
embstr与raw的区别
embstr是专门用于保存短字符串的一种编码方式,这种编码和raw编码一样都是使用RedisObjecthe和sdshdr结构表示字符串,但是raw会调用两次内存分配函数分别创建RedisObjecthe和sdshdr结构,而embstr则通过一次内存分配函数创建
字符串常用命令 SET、GET
列表对象
列表对象的编码可以是ziplist或者linkedlist
- ziplist编码的列表对象可以是使用压缩列表作为底层实现每个压缩列表保存一个列表元素
- linkedlist编码的列表对象使用双端列表作为底层实现,每个双端链表节点(node)都保存了一个字符串对象,每个字符串对象保存了一个列表元素
字符串对象是Redis五种类型对象当中唯一一种会被其他四种对象嵌套使用的对象
编码转换
列表对象满足一下两个条件时,使用ziplist编码
- 列表对象保存的所有字符串元素的长度都小于64字节;
- 列表对象保存的元素数量小于512个;
不能满足以上两个条件的列表对象都需要使用linkedlist编码
列表对象常用命令 LPUSH、RPUSH、LPOP、RPOP
哈希对象
哈希对象编码可以使用ziplist或者hashtable
编码转换
当哈希对象可以满足一下两个条件时,哈希对象使用ziplist编码
- 哈希对象保存的键值对的键和值的字符串长度都小于64个字节;
- 哈希对象保存的键值对的数量小于512个;
不能满足以上两个条件的哈希对象则使用hashtable编码
哈希对象常用的命令HSET、HGET
集合对象
集合对象的编码使用的可以是intset或者hashtable
编码转换
当集合对象满足一下两个条件时,对象使用intset编码
- 集合对象所有元素都是整型
- 集合对象保存的元素数量不超过512个
不能满足这两个条件的集合对象使用hashtable编码
集合常见命令:SCARD、SPOP
有序集合对象
有序集合的编码可以是ziplist和skiplist
压缩列表内的集合元素按照分值大小进行排序,分值比较小的元素被放置在靠近表头的位置,而分值比较大的元素则被放置到靠近表尾的位置
skiplist编码的有序集合对象使用zset机构作为底层实现,一个zset机构同时包含一个字典和一个跳跃表
编码转换
当有序集合对象满足一下两个条件时,对象使用ziplist编码
- 有序集合保存元素数量小于128个
- 有序集合保存的所有元素成员长度都小于64字节
不能满足以上两个条件集合的有序集合对象使用skiplist编码
有序集合常见命令ZADD、ZCARD、ZREM
Redis对象内存回收
Redis在自己的系统中构建了一个引用计数实现的内存回收机制,通过这个机制,程序可以通过跟踪对象的引用计数信息,在适当的时候自动释放对象并进行内存回收
Redis在初始化服务器时,创建一万个字符串对象,这些对象包含了从0到9999的所有整型值,当服务器需要从0到9999的字符串对象时候,服务器就会使用这些共享对象,而不是创建新的对象
redis关于内存回收,采用了lru算法,根据当前对象的lru 参数值来进行淘汰计算。