简介

本书对 Redis 的大多数单机功能以及所有多机功能的实现原理进行了介绍, 展示了这些功能的核心数据结构以及关键的算法思想。

通过阅读本书, 读者可以快速、有效地了解 Redis 的内部构造以及运作机制, 这些知识可以帮助读者更好地、也更高效地使用 Redis 。

为了让本书的内容保持简单并且容易读懂, 本书会尽量以高层次的角度来对 Redis 的实现原理进行描述, 如果读者只是对 Redis 的实现原理感兴趣, 但并不想研究 Redis 的源代码, 那么阅读本书就足够了。

另一方面, 如果读者打算深入了解 Redis 实现原理的底层细节, 本书在 RedisBook.com 提供了一份带有详细注释的 Redis 源代码, 读者可以先阅读本书对某一功能的介绍, 然后再阅读该功能对应的实现代码, 这有助于读者更快地读懂实现代码, 也有助于读者更深入地了解该功能的实现原理。

版本说明

本书是基于 Redis 2.9 —— 也即是 Redis 3.0 的开发版来编写的, 因为 Redis 3.0 的更新主要与 Redis 的多机功能有关, 而 Redis 3.0 的单机功能则与 Redis 2.6 、Redis 2.8 的单机功能基本相同, 所以本书的内容对于使用 Redis 2.6 至 Redis 3.0 的读者来说应该都是有用的。

另外, 因为 Redis 通常都是渐进地增加新功能, 并且很少会大幅地修改已有的功能, 所以本书的大部分内容对于 Redis 3.0 之后的几个版本来说, 应该也是有用的。

章节编排

本书由《数据结构与对象》、《单机数据库的实现》、《多机数据库的实现》、《独立功能的实现》四个部分组成。

第一部分

Redis 数据库里面的每个键值对(key-value pair)都是由对象(object)组成的:

  • 其中, 数据库键总是一个字符串对象(string object);

  • 而数据库键的值则可以是字符串对象、 列表对象(list object)、 哈希对象(hash object)、 集合对象(set object)、 有序集合对象(sorted set object)这五种对象中的其中一种。

比如说, 执行以下命令将在数据库中创建一个键为字符串对象, 值也为字符串对象的键值对:

redis> SET msg "hello world"
OK

而执行以下命令将在数据库中创建一个键为字符串对象, 值为列表对象的键值对:

redis> RPUSH numbers 1 3 5 7 9
(integer) 5

本书的第一部分 —— 也即是《数据结构与对象》部分, 将对以上提到的五种不同类型的对象进行介绍, 剖析这些对象所使用的底层数据结构, 并说明这些数据结构是如何深刻地影响对象的功能和性能的。

第二部分

本书的第二部分 —— 也即是《单机数据库的实现》部分, 对 Redis 实现单机数据库的方法进行了介绍。

《数据库》一章对 Redis 数据库的实现原理进行了介绍: 说明了服务器保存键值对的方法, 服务器保存键值对过期时间的方法, 以及服务器自动删除过期键值对的方法, 等等。

《RDB 持久化》和《AOF 持久化》两章分别介绍了 Redis 两种不同的持久化方式的实现原理: 说明了服务器根据数据库来生成持久化文件的方法, 服务器根据持久化文件来还原数据库的方法, 以及 BGSAVE 命令和 BGREWRITEAOF 命令的实现原理, 等等。

《事件》一章对 Redis 的文件事件和时间事件进行了介绍:

  • 文件事件主要用于应答(accept)客户端的连接请求, 接收客户端发送的命令请求, 以及向客户端返回命令回复;

  • 而时间事件则主要用于执行 redis.c/serverCron 函数 —— 这个函数通过执行常规的维护和管理操作来保持 Redis 服务器的正常运作, 一些重要的定时操作也是由这个函数负责触发的。

《客户端》一章对 Redis 服务器维护和管理客户端状态的方法进行了介绍: 列举了客户端状态包含的各个属性, 说明了客户端的输入缓冲区和输出缓冲区的实现方法, 以及 Redis 服务器创建和销毁客户端状态的条件, 等等。

《服务器》一章对单机 Redis 服务器的运作机制进行了介绍: 详细地说明了服务器处理命令请求的步骤, 解释了 serverCron 函数所做的工作, 并讲解了 Redis 服务器的初始化过程。

第三部分

本书的第三部分 —— 也即是《多机数据库的实现》部分, 对 Redis 的 Sentinel 、复制(replication)、集群(cluster)三个多机功能进行了介绍。

《Sentinel》一章对 Redis Sentinel 的实现原理进行了介绍: 说明了 Sentinel 监视服务器的方法, Sentinel 判断服务器是否下线的方法, 以及 Sentinel 对下线服务器进行故障转移的方法, 等等。

《复制》一章对 Redis 的主从复制功能(master-slave replication)的实现原理进行了介绍: 说明了当用户指定一个服务器(从服务器)去复制另一个服务器(主服务器)时, 主从服务器之间执行了什么操作, 进行了什么数据交互, 诸如此类。

《集群》一章对 Redis 集群的实现原理进行了介绍: 说明了节点(node)的构建方法, 节点处理命令请求的方法, 转发(redirection)错误的实现方法, 以及各个节点之间进行通讯的方法, 等等。

第四部分

本书的第四部分 —— 也即是《独立功能的实现》部分, 对 Redis 中各个相对独立的功能模块进行了介绍。

《发布与订阅》一章对 PUBLISHSUBSCRIBEPUBSUB 等命令的实现原理进行了介绍, 解释了 Redis 的发布与订阅功能是如何实现的。

《事务》一章对 MULTIEXECWATCH 等命令的实现原理进行了介绍, 解释了 Redis 的事务是如何实现的, 并说明了 Redis 的事务对 ACID 性质的支持程度。

《Lua 脚本》一章对 EVALEVALSHASCRIPT_LOAD 等命令的实现原理进行了介绍, 解释了 Redis 服务器是如何执行和管理用户传入的 Lua 脚本的; 这一章还对 Redis 服务器构建 Lua 环境的过程, 以及主从服务器之间复制 Lua 脚本的方法进行了介绍。

《排序》一章对 SORT 命令、 以及 SORT 命令所有可用选项(比如 DESCALPHAGET ,等等)的实现原理进行了介绍, 并说明了当 SORT 命令带有多个选项时, 不同选项执行的先后顺序。

《二进制位数组》一章对 Redis 保存二进制位数组的方法进行了介绍, 并说明了 GETBITSETBITBITCOUNTBITOP 这几个二进制位数组操作命令的实现原理。

《慢查询日志》一章对 Redis 创建和保存慢查询日志(slow log)的方法进行了介绍, 并说明了 SLOWLOG GETSLOWLOG LENSLOWLOG RESET 等慢查询日志操作命令的实现原理。

《监视器》一章介绍了将客户端变为监视器(monitor)的方法, 以及服务器在处理命令请求时, 向监视器发送命令信息的方法。

推荐的阅读方法

因为 Redis 的单机功能是多机功能的子集, 所以无论读者使用的是单机模式的 Redis , 还是多机模式的 Redis , 都应该阅读本书的第一部分和第二部分, 也即是《数据结构与对象》部分和《单机数据库的实现》部分, 这两个部分包含的知识是所有 Redis 使用者都必然会用到的。

如果读者要使用 Redis 的多机功能, 那么在阅读本书的第一部分和第二部分之后, 应该接着阅读本书的第三部分, 也即是《多机数据库的实现》部分; 相反地, 如果读者只使用 Redis 的单机功能, 那么可以跳过第三部分, 直接阅读第四部分。

本书的前三个部分都是以自底向上(bottom-up)的方式来写的, 也就是说, 排在后面的章节会假设读者已经读过了排在前面的章节: 如果一个概念在前面的章节已经介绍过, 那么后面的章节就不会再重复介绍这个概念, 所以读者最好按顺序阅读这三部分的各个章节。

本书的第四部分 —— 也即是《独立功能的实现》部分包含的各章是完全独立的, 读者可以按自己的兴趣来挑选要读的章节。

在本书的第四部分中, 除了《Lua 脚本》一章的其中一节有涉及多机功能的内容之外, 其他章节都没有涉及多机功能的内容, 所以第四部分的大部分内容都可以在只阅读了本书第一部分和第二部分的情况下阅读。

图 1-1 对上面描述的阅读方法进行了总结。

digraph {

    label = "\n 图 1-1    推荐的阅读方法"

    node [shape = box]

    read_part_one [label = "按顺序阅读《数据结构与对象》部分的所有章节"]

    read_part_two [label = "按顺序阅读《单机数据库的实现》部分的所有章节"]

    multi_or_not [label = "你要用到 Redis 的\n多机功能吗?", shape = diamond]

    read_part_three [label = "按顺序阅读《多机数据库的实现》部分的所有章节"]

    read_part_four [label = "挑选《独立功能的实现》部分中\n你喜欢的章节来进行阅读"]

    read_part_one -> read_part_two -> multi_or_not;

    multi_or_not -> read_part_three [label = "是"]

    multi_or_not -> read_part_four [label = "否"]

    read_part_three -> read_part_four

}

行文规则

名字引用规则

在第一次引用 Redis 源代码文件 file 中的名字 name 时, 本书使用 file/name 格式: 比如 redis.c/main 表示 redis.c 文件中的 main 函数, 而 redis.h/redisDb 则表示 redis.h 文件中的 redisDb 结构, 诸如此类。

另外, 在第一次引用标准库头文件 file 中的名字 name 时, 本书使用 <file>/name 格式: 比如 <unistd.h>/write 表示 unistd.h 头文件的 write 函数, 而 <stdio.h>/printf 则表示 stdio.h 头文件的 printf 函数, 诸如此类。

在第一次引用某个名字之后, 本书就会去掉名字前缀的文件名, 直接使用名字本身。

举个例子, 当本书第一次引用 redis.h 文件的 redisDb 结构的时候, 本书会使用 redis.h/redisDb 格式, 而之后再次引用 redisDb 结构时, 本书只使用名字 redisDb

结构引用规则

本书使用 struct.property 格式来引用 struct 结构的 property 属性: 比如 redisDb.id 表示 redisDb 结构的 id 属性, 而 redisDb.expires 则表示 redisDb 结构的 expires 属性, 诸如此类。

算法规则

除非有额外说明, 否则本书列出的算法复杂度一律为最坏情形下的算法复杂度。

代码规则

本书使用 C 语言和 Python 语言来展示代码:

  • 在描述数据结构以及比较简短的代码时, 本书通常会直接粘贴 Redis 的源代码, 也即是 C 语言代码。

  • 相反地, 当需要使用代码来描述比较长或者比较复杂的程序时, 本书通常会使用 Python 语言来表示伪代码。

本书展示的 Python 伪代码中通常会包含 serverclient 两个全局变量: 其中 server 表示服务器状态(redis.h/redisServer 结构的实例), 而 client 则表示正在执行操作的客户端状态(redis.h/redisClient 结构的实例)。

配套网站

本书带有配套网站 RedisBook.com , 这个网站记录了本书的最新消息, 并且提供了附带详细注释的 Redis 源代码可供下载, 读者也可以通过这个网站查看和反馈本书的勘误, 或者发表与本书有关的问题、意见、以及建议。