深入了解Redis【二】对象及数据结构综述
引言
Redis中每个键值对都是由对象组成:
- 键总是一个字符串对象(string)
- 值可以是字符串对象(string)、列表对象(list)、哈希对象(hash)、集合对象(set)、有序集合对象(zset)。
1、介绍
redis官方网站中对其数据类型的简单介绍:
An introduction to Redis data types and abstractions
摘抄一段关于redis key的介绍:
Redis keys
Redis keys are binary safe, this means that you can use any binary sequence as a key, from a string like “foo” to the content of a JPEG file. The empty string is also a valid key.
A few other rules about keys:
- Very long keys are not a good idea. For instance a key of 1024 bytes is a bad idea not only memory-wise, but also because the lookup of the key in the dataset may require several costly key-comparisons. Even when the task at hand is to match the existence of a large value, hashing it (for example with SHA1) is a better idea, especially from the perspective of memory and bandwidth.
- Very short keys are often not a good idea. There is little point in writing “u1000flw” as a key if you can instead write “user:1000:followers”. The latter is more readable and the added space is minor compared to the space used by the key object itself and the value object. While short keys will obviously consume a bit less memory, your job is to find the right balance.
- Try to stick with a schema. For instance “object-type:id” is a good idea, as in “user:1000”. Dots or dashes are often used for multi-word fields, as in “comment:1234:reply.to” or “comment:1234:reply-to”.
- The maximum allowed key size is 512 MB.
2、源码中的对象数据结构
在redis源码中,对象的数据结构定义在redis.h文件中
1 |
|
下面分别介绍以下对象中定义的属性定义:
- type
type是指对象的5种基本类型:string、hash、list、set、zset。1
2
3
4
5
6// 对象类型
- encoding
表示对象的底层编码实现,有简单动态字符串、链表、字典、跳跃表、整数集合、压缩列表。1
2
3
4
5
6
7
8
9
10// 对象编码
- lru
最后一次访问对象的时间,用来处理键的过期策略。 - refcount
对象引用的指针,不同key的相同对象引用同一个对象,减少内存分配即对象共享。也用于内存释放。 - *ptr
指向底层数据结构的指针。
3、基本类型type与底层数据结构的对应关系
盗取一张图(懒的画图):
各种对象的创建可以参考redis源码中的object.c文件,如:
根据传入的整数型,创建一个字符串:
1 | /* |
下面简单看看基本类型type对应的底层数据结构:
3.1、string
sting在redis底层对应三种编码方式,两种数据结构。
如果一个字符串内容可以转成long,那么编码方式为int,底层数据结构为int.
如果普通字符串对象的长度小于39字节,就用embstr对象。否则用的raw对象,底层数据结构为简单动态字符串。
1 | /* Create a string object with EMBSTR encoding if it is smaller than |
3.1.1、SDS
简单动态字符串(simple dynamic string)的数据结构为:
1 | /* |
3.2、list
有两种编码实现,链表linkedlist和压缩列表ziplist,当list元素少且元素内容长度不大时,使用ziplist,否则使用linkedlist.
1 | /* Use a real list when there are too many entries |
3.2.1、链表linkedlist
其底层数据结构list位于adlist.h中:
1 | /* |
3.2.2、压缩列表ziplist
类似数组,但是每个节点存储的数据大小不同,节点上有length属性。
3.3、hash
有两种数据结构实现,压缩列表ziplist和字典dict.
3.3.1、字典dict
相当于java中的HashMap。解决hash冲突使用的是链表法,好像没有上升到红黑树。
3.4、set
如果是整数类型,直接使用整数集合intset,如果不是,就用字典,和java的set一样。
3.5、zset
有序的set,元素个数少且不大,就用压缩列表ziplist,否则就用跳跃表skiplist.
3.5.1、跳跃表skiplist
跳跃表(skiplist)是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。
跳跃表是一种随机化的数据,跳跃表以有序的方式在层次化的链表中保存元素。
定义位于redis.h中。
1 |
|
参考文档
深入浅出Redis-redis底层数据结构(上)
深入浅出Redis-redis底层数据结构(下)
Redis基本类型及其数据结构
Redis的五种对象类型及其底层实现
Redis-基本数据类型与内部存储结构
redis的五种基本数据类型及其内部实现
《Redis设计与实现》黄健宏