redis 数据结构与对象

 简单动态字符串

Redis 没有直接使用 C 语言传统的字符串表示(以空字符结尾的字符数组,以下简称 C 字符串),而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS)的抽象类型,并将 SDS 用作 Redis 的默认字符串表示。

 

在 Redis 里面, C 字符串只会作为字符串字面量(string literal),用在一些无须对字符串值进行修改的地方,比如打印日志:

 

redisLog(REDIS_WARNING,"Redis is nowready to exit, bye bye...");

当 Redis 需要的不仅仅是一个字符串字面量,而是一个可以被修改的字符串值时, Redis 就会使用 SDS 来表示字符串值:比如在 Redis 的数据库里面,包含字符串值的键值对在底层都是由 SDS 实现的。

 

举个例子,如果客户端执行命令:

 

redis> SET msg "hello world"

OK

那么 Redis 将在数据库中创建了一个新的键值对,其中:

 

键值对的键是一个字符串对象,对象的底层实现是一个保存着字符串 "msg" 的 SDS 。

键值对的值也是一个字符串对象,对象的底层实现是一个保存着字符串 "hello world" 的 SDS 。

又比如说,如果客户端执行命令:

 

redis> RPUSH fruits "apple""banana" "cherry"

(integer) 3

那么 Redis 将在数据库中创建一个新的键值对,其中:

 

键值对的键是一个字符串对象,对象的底层实现是一个保存了字符串 "fruits" 的 SDS 。

键值对的值是一个列表对象,列表对象包含了三个字符串对象,这三个字符串对象分别由三个 SDS 实现:第一个 SDS 保存着字符串 "apple" ,第二个 SDS 保存着字符串 "banana" ,第三个 SDS 保存着字符串 "cherry" 。

除了用来保存数据库中的字符串值之外, SDS 还被用作缓冲区(buffer): AOF 模块中的AOF 缓冲区,以及客户端状态中的输入缓冲区,都是由 SDS 实现的,在之后介绍 AOF 持久化和客户端状态的时候,我们会看到 SDS 在这两个模块中的应用。

 

本章接下来将对 SDS 的实现进行介绍,说明 SDS 和 C 字符串的不同之处,解释为什么 Redis 要使用 SDS 而不是 C 字符串,并在本章的最后列出 SDS 的操作 API 。

 

 

链表

链表提供了高效的节点重排能力,以及顺序性的节点访问方式,并且可以通过增删节点来灵活地调整链表的长度。

 

作为一种常用数据结构,链表内置在很多高级的编程语言里面,因为 Redis 使用的 C 语言并没有内置这种数据结构,所以 Redis 构建了自己的链表实现。

 

链表在 Redis 中的应用非常广泛,比如列表键的底层实现之一就是链表:当一个列表键包含了数量比较多的元素,又或者列表中包含的元素都是比较长的字符串时, Redis 就会使用链表作为列表键的底层实现。

 

举个例子,以下展示的 integers 列表键包含了从 1 到 1024 共一千零二十四个整数:

 

redis> LLEN integers

(integer) 1024

 

redis> LRANGE integers 0 10

1) "1"

2) "2"

3) "3"

4) "4"

5) "5"

6) "6"

7) "7"

8) "8"

9) "9"

10) "10"

11) "11"

integers 列表键的底层实现就是一个链表, 链表中的每个节点都保存了一个整数值。

 

除了链表键之外,发布与订阅、慢查询、监视器等功能也用到了链表, Redis 服务器本身还使用链表来保存多个客户端的状态信息,以及使用链表来构建客户端输出缓冲区(output buffer),本书后续的章节将陆续对这些链表应用进行介绍。

 

因为已经有很多优秀的算法书籍对链表的基本定义和相关算法进行了详细的讲解,所以本章不会介绍这些内容,如果不具备关于链表的基本知识的话,可以参考《算法:C 语言实现(第 1 ~ 4 部分)》一书的 3.3 至 3.5 节,或者《数据结构与算法分析:C 语言描述》一书的 3.2 节,又或者《算法导论(第三版)》一书的 10.2 节。

 

 

 

 

»

字典

字典,又称符号表(symbol table)、关联数组(associative array)或者映射(map),是一种用于保存键值对(key-value pair)的抽象数据结构。

 

在字典中,一个键(key)可以和一个值(value)进行关联(或者说将键映射为值),这些关联的键和值就被称为键值对。

 

字典中的每个键都是独一无二的,程序可以在字典中根据键查找与之关联的值,或者通过键来更新值,又或者根据键来删除整个键值对,等等。

 

字典经常作为一种数据结构内置在很多高级编程语言里面,但 Redis 所使用的 C 语言并没有内置这种数据结构,因此 Redis 构建了自己的字典实现。

 

字典在 Redis 中的应用相当广泛,比如 Redis 的数据库就是使用字典来作为底层实现的,对数据库的增、删、查、改操作也是构建在对字典的操作之上的。

 

举个例子,当我们执行命令:

 

redis> SET msg "hello world"

OK

在数据库中创建一个键为 "msg" ,值为 "hello world" 的键值对时, 这个键值对就是保存在代表数据库的字典里面的。

 

除了用来表示数据库之外,字典还是哈希键的底层实现之一:当一个哈希键包含的键值对比较多,又或者键值对中的元素都是比较长的字符串时, Redis 就会使用字典作为哈希键的底层实现。

 

举个例子, website 是一个包含 10086 个键值对的哈希键,这个哈希键的键都是一些数据库的名字,而键的值就是数据库的主页网址:

 

redis> HLEN website

(integer) 10086

 

redis> HGETALL website

1) "Redis"

2) "Redis.io"

3) "MariaDB"

4) "MariaDB.org"

5) "MongoDB"

6) "MongoDB.org"

# ...

website 键的底层实现就是一个字典, 字典中包含了 10086 个键值对:

 

其中一个键值对的键为 "Redis" ,值为 "Redis.io" 。

另一个键值对的键为 "MariaDB" ,值为 "MariaDB.org" ;

还有一个键值对的键为 "MongoDB" ,值为 "MongoDB.org" ;

诸如此类。

 

除了用来实现数据库和哈希键之外, Redis 的不少功能也用到了字典,在后续的章节中会不断地看到字典在 Redis 中的各种不同应用。

维基百科的 Associative Array 词条(http://en.wikipedia.org/wiki/Associative_array)和 Hash Table词条(http://en.wikipedia.org/wiki/Hash_table)。

《算法:C 语言实现(第 1 ~ 4 部分)》一书的第 14 章。

《算法导论(第三版)》一书的第 11 章。

 

 

 

 

indexRedis  »

整数集合

整数集合(intset)是集合键的底层实现之一:当一个集合只包含整数值元素,并且这个集合的元素数量不多时, Redis 就会使用整数集合作为集合键的底层实现。

 

举个例子,如果我们创建一个只包含五个元素的集合键,并且集合中的所有元素都是整数值,那么这个集合键的底层实现就会是整数集合:

 

redis> SADD numbers 1 3 5 7 9

(integer) 5

 

redis> OBJECT ENCODING numbers

 

 

 

 

 

indexRedis  »

整数集合

整数集合(intset)是集合键的底层实现之一:当一个集合只包含整数值元素,并且这个集合的元素数量不多时, Redis 就会使用整数集合作为集合键的底层实现。

 

举个例子,如果我们创建一个只包含五个元素的集合键,并且集合中的所有元素都是整数值,那么这个集合键的底层实现就会是整数集合:

 

redis> SADD numbers 1 3 5 7 9

(integer) 5

 

redis> OBJECT ENCODING numbers

"intset"

 

 

 

 

 

 

 

 

indexRedis  »

整数集合

整数集合(intset)是集合键的底层实现之一:当一个集合只包含整数值元素,并且这个集合的元素数量不多时, Redis 就会使用整数集合作为集合键的底层实现。

 

举个例子,如果我们创建一个只包含五个元素的集合键,并且集合中的所有元素都是整数值,那么这个集合键的底层实现就会是整数集合:

 

redis> SADD numbers 1 3 5 7 9

(integer) 5

 

redis> OBJECT ENCODING numbers

"intset"

 

 

 

 

 

indexRedis  »

对象

在前面的数个章节里,我们陆续介绍了 Redis 用到的所有主要数据结构,比如简单动态字符串(SDS)、双端链表、字典、压缩列表、整数集合,等等。

 

Redis 并没有直接使用这些数据结构来实现键值对数据库, 而是基于这些数据结构创建了一个对象系统, 这个系统包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象这五种类型的对象,每种对象都用到了至少一种我们前面所介绍的数据结构。

 

通过这五种不同类型的对象, Redis 可以在执行命令之前,根据对象的类型来判断一个对象是否可以执行给定的命令。使用对象的另一个好处是,我们可以针对不同的使用场景,为对象设置多种不同的数据结构实现,从而优化对象在不同场景下的使用效率。

 

除此之外, Redis 的对象系统还实现了基于引用计数技术的内存回收机制:当程序不再使用某个对象的时候,这个对象所占用的内存就会被自动释放;另外, Redis 还通过引用计数技术实现了对象共享机制,这一机制可以在适当的条件下,通过让多个数据库键共享同一个对象来节约内存。

 

最后, Redis 的对象带有访问时间记录信息,该信息可以用于计算数据库键的空转时长,在服务器启用了 maxmemory 功能的情况下,空转时长较大的那些键可能会优先被服务器删除。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值