在redis中主要用到的数据结构包括了简单动态字符串(SDS)
,双端链表
,字典
,压缩列表
,整数集合
等。
在redis中没有直接使用这些数据结构来实现键值对数据库, 而是基于这些数据结构创建一个对象系统
. 这个系统包含了字符串对象
,列表对象
,,集合对象
和有序集合对象
五中类型。每种对象都用到了至少一种数据结构。
对象优点
-
通过这五中不同类型的对象, Redis可以在执行命令之前, 根据对象的类型来判断一个对象是否可以执行给定的领命。
-
可以针对不同的使用场景, 为对象设置多种不同的数据结构实现,从而优化对象在不同场景下的使用效率。
内存回收机制
-
Redis对象系统基于
引用计数法
对内存进行回收。 当程序不在使用某个对象的时候, 这个对象所占用的内存就会被自动释放; -
Redis还通过
引用计数
实现对象共享机制, 可以在适当条件下, 通过让多个数据库共享同一个对象来节约内存。
对象抛弃策略
Redis对象带有访问时间记录信息, 该信息可以用于计算数据库键的空转时长, 在服务器启用了maxmemory
功能情况下, 空转时长较大的那些键可能会优先被服务器删除。
对象类型要编码策略
对象的创建
当我们在想Redis中创建一个键值对时, 我们至少会创建两个对象
-
键对象: 用于存储键值对中的键信息
-
值对象: 用于存储键值对中的值信息
对象的定义
typedef struct redisObject { // 类型 unsigned type:4; // 编码 unsigned encoding:4; // 指向底层实现数据结构的指针 void *ptr; }
Redis中每个对象由一个redisObject结构表示, 该结构中和保存数据有关的三个属性分别是type
,encoding
和ptr
属性。
类型
对象的type
属性记录了对象的类型。
类型常量 | 对象的名称 |
---|---|
REDIS_STRING | 字符串对象 |
REDIS_LIST | 列表对象 |
REDIS_HASH | 哈希对象 |
REDIS_SET | 集合对象 |
REDIS_ZSET | 有序集合对象 |
对于Redis数据库保存的键值对来说, 键总是一个字符串对象, 而值则可以是字符串对象
,列表对象
,哈希对象
,集合对象
,有序集合对象
中的一种。
type
命令可以查看Redis中值对象的类型:
> RPUSH numbers 1 3 5 > TYPE msg list
对象 | 对象type属性的值 | TYPE命令的输出 |
---|---|---|
字符串对象 | REDIS_STRING | “string” |
列表对象 | REDIS_LIST | “list” |
哈希对象 | REDIS_HASH | “hash” |
集合对象 | REDIS_SET | “set” |
有序集合对象 | REDIS_ZSET | “zset” |
编码与底层实现
对象ptr
指针指向对象的底层实现数据结构, 而这些数据结构由对象的encoding
属性决定.
编码常量 | 编码所对应的底层数据结构 |
---|---|
REDIS_ENCODING_INT | long类型的整数 |
REDIS_ENCODING_EMBSTR | embtr编码的简单动态字符串 |
REDIS_ENCODING_RAW | 简单动态字符串 |
REDIS_ENCODING_HT | 字典 |
REDIS_ENCODING_LINKEDLIST | 双端链表 |
REDIS_ENCODING_ZIPLIST | 压缩列表 |
REDIS_ENCODING_INTSET | 整数集合 |
REDIS_ENCODING_SKIPLIST | 跳跃表和字典 |
每种类型至少使用两种中不同的编码:
类型 | 编码 | 对象 |
---|---|---|
REDIS_STRING | REDIS_ENCODING_INT | 使用整数值实现的字符串对象 |
REDIS_STRING | REDIS_ENCODING_EMBSTR | 使用embstr编码的简单动态字符串实现的字符串对象 |
REDIS_STRING | REDIS_ENCODING_RAW | 简单动态字符串实现的字符串对象 |
REDIS_LIST | REDIS_ENCODING_ZIPLIST | 使用压缩列表实现的列表对象 |
REDIS_LIST | REDIS_ENCODING_LINKEDLIST | 使用双端链表实现的列表对象 |
REDIS_HASH | REDIS_ENCODING_ZIPLIST | 使用压缩列表实现的哈希对象 |
REDIS_HASH | REDIS_ENCODING_HT | 使用字典实现的hash对象 |
REDIS_SET | REDIS_ENCODING_INTSET | 使用整数集合实现的集合对象 |
REDIS_SET | REDIS_ENCODING_HT | 使用字典实现的集合对象 |
REDIS_ZSET | REDIS_ENCODING_ZIPLIST | 使用压缩列表实现的有序集合对象 |
REDIS_ZSET | REDIS_ENCODING_SKIPLIST | 使用跳跃表和字典实现的有序集合对象 |
NOTE: 可以通过
OBJECT ENCODING
查看键值对象中的值对象的编码。
通过encoding
属性来设定对象所使用的编码, 而不是为特定类型的对象关联一种固定的编码, 极大地提升了Redis的灵活性和效率, 因为Redis可以根据不同的使用场景来为一个对象设置不同的编码.
压缩列表和双端队列比较
-
压缩列表比双端队列更节约内存, 并且在元素数量较少时, 在内存中以连续块方式保存的压缩列表比起双端链表可以更快被载入到缓存中.
-
随着列表对象包含的元素越来越多, 使用压缩列表来保存元素的优势组件消失时, 对象就汇将底层实现从压缩列表向功能更强, 也适合保存大量元素的双端链表上面。