介绍
Redis并没有直接使用数据结构来实现键值对数据库.而是基于这些数据结构创建了对象系统.
- 字符串对象
- 列表对象
- hash对象
- 集合对象
- 有序集合对象
每种对象基本对应两种或者两种以上的数据结构实现.
回收和共享
使用引用计数法实现内存的回收.引用计数技术还可以实现对象的共享.多个数据库共享一个对象来节约内存.
访问时间记录
Redis的对象带有访问时间记录信息,可以计算数据库键的空转时长,在开启了maxmemory后可以优先删除
类型与编码
typedef struct redisObject{
// 类型
unsigned type:4;
// 类型编码
unsigned encoding:4;
// 指向底层数据结构的指针
void *ptr
.....
} robj;
对象类型
type属性记录了对象的类型.
| 类型常量 | 对象的名称 |
| :------------- | :----------- |
| `REDIS_STRING` | 字符串对象 |
| `REDIS_LIST` | 列表对象 |
| `REDIS_HASH` | 哈希对象 |
| `REDIS_SET` | 集合对象 |
| `REDIS_ZSET` | 有序集合对象 |
对于 Redis 数据库保存的键值对来说, 键总是一个字符串对象, 而值则可以是字符串对象、列表对象、哈希对象、集合对象或者有序集合对象的其中一种, 因此:
- 当我们称呼一个数据库键为“字符串键”时, 我们指的是“这个数据库键所对应的值为字符串对象”;
- 当我们称呼一个键为“列表键”时, 我们指的是“这个数据库键所对应的值为列表对象”
可以使用TYPE
命令查看
redis> ZADD price 8.5 apple 5.0 banana 6.0 cherry
(integer) 3
redis> TYPE price
zset
ptr指针
对象的 ptr
指针指向对象的底层实现数据结构, 而这些数据结构由对象的 encoding
属性决定
| 编码常量 | 编码所对应的底层数据结构 |
| :-------------------------- | :---------------------------- |
| `REDIS_ENCODING_INT` | `long` 类型的整数 |
| `REDIS_ENCODING_EMBSTR` | `embstr` 编码的简单动态字符串 |
| `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` | 使用字典实现的哈希对象。 |
| | | |
| `REDIS_SET` | `REDIS_ENCODING_INTSET` | 使用整数集合实现的集合对象。 |
| `REDIS_SET` | `REDIS_ENCODING_HT` | 使用字典实现的集合对象。 |
| | | |
| `REDIS_ZSET` | `REDIS_ENCODING_ZIPLIST` | 使用压缩列表实现的有序集合对象。 |
| `REDIS_ZSET` | `REDIS_ENCODING_SKIPLIST` | 使用跳跃表和字典实现的有序集合对象。(字典是为了O(1)读取) |
使用 OBJECT ENCODING
命令可以查看一个数据库键的值对象的编码
通过 encoding
属性来设定对象所使用的编码, 而不是为特定类型的对象关联一种固定的编码, 极大地提升了 Redis 的灵活性和效率, 因为 Redis 可以根据不同的使用场景来为一个对象设置不同的编码, 从而优化对象在某一场景下的效率。
举个例子, 在列表对象包含的元素比较少时, Redis 使用压缩列表作为列表对象的底层实现:
- 因为压缩列表比双端链表更节约内存, 并且在元素数量较少时, 在内存中以连续块方式保存的压缩列表比起双端链表可以更快被载入到缓存中;
- 随着列表对象包含的元素越来越多, 使用压缩列表来保存元素的优势逐渐消失时, 对象就会将底层实现从压缩列表转向功能更强、也更适合保存大量元素的双端链表上面;