# 简介
本书对 Redis 的大多数单机功能以及所有多机功能的实现原理进行了介绍, 展示了这些功能的核心数据结构以及关键的算法思想。
通过阅读本书, 读者可以快速、有效地了解 Redis 的内部构造以及运作机制, 这些知识可以帮助读者更好地、也更高效地使用 Redis 。
为了让本书的内容保持简单并且容易读懂, 本书会尽量以高层次的角度来对 Redis 的实现原理进行描述, 如果读者只是对 Redis 的实现原理感兴趣, 但并不想研究 Redis 的源代码, 那么阅读本书就足够了。
另一方面, 如果读者打算深入了解 Redis 实现原理的底层细节, 本书在 [RedisBook.com](http://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 中各个相对独立的功能模块进行了介绍。
《发布与订阅》一章对 PUBLISH 、 SUBSCRIBE 、 PUBSUB 等命令的实现原理进行了介绍, 解释了 Redis 的发布与订阅功能是如何实现的。
《事务》一章对 MULTI 、 EXEC 、 WATCH 等命令的实现原理进行了介绍, 解释了 Redis 的事务是如何实现的, 并说明了 Redis 的事务对 ACID 性质的支持程度。
《Lua 脚本》一章对 EVAL 、 EVALSHA 、 SCRIPT_LOAD 等命令的实现原理进行了介绍, 解释了 Redis 服务器是如何执行和管理用户传入的 Lua 脚本的; 这一章还对 Redis 服务器构建 Lua 环境的过程, 以及主从服务器之间复制 Lua 脚本的方法进行了介绍。
《排序》一章对 SORT 命令、 以及 SORT 命令所有可用选项(比如 `DESC` 、 `ALPHA` 、 `GET` ,等等)的实现原理进行了介绍, 并说明了当SORT 命令带有多个选项时, 不同选项执行的先后顺序。
《二进制位数组》一章对 Redis 保存二进制位数组的方法进行了介绍, 并说明了 GETBIT 、 SETBIT 、 BITCOUNT 、 BITOP 这几个二进制位数组操作命令的实现原理。
《慢查询日志》一章对 Redis 创建和保存慢查询日志(slow log)的方法进行了介绍, 并说明了 SLOWLOG GET 、 SLOWLOG LEN 、SLOWLOG RESET 等慢查询日志操作命令的实现原理。
《监视器》一章介绍了将客户端变为监视器(monitor)的方法, 以及服务器在处理命令请求时, 向监视器发送命令信息的方法。
## 推荐的阅读方法
因为 Redis 的单机功能是多机功能的子集, 所以无论读者使用的是单机模式的 Redis , 还是多机模式的 Redis , 都应该阅读本书的第一部分和第二部分, 也即是《数据结构与对象》部分和《单机数据库的实现》部分, 这两个部分包含的知识是所有 Redis 使用者都必然会用到的。
如果读者要使用 Redis 的多机功能, 那么在阅读本书的第一部分和第二部分之后, 应该接着阅读本书的第三部分, 也即是《多机数据库的实现》部分; 相反地, 如果读者只使用 Redis 的单机功能, 那么可以跳过第三部分, 直接阅读第四部分。
本书的前三个部分都是以自底向上(bottom-up)的方式来写的, 也就是说, 排在后面的章节会假设读者已经读过了排在前面的章节: 如果一个概念在前面的章节已经介绍过, 那么后面的章节就不会再重复介绍这个概念, 所以读者最好按顺序阅读这三部分的各个章节。
本书的第四部分 —— 也即是《独立功能的实现》部分包含的各章是完全独立的, 读者可以按自己的兴趣来挑选要读的章节。
在本书的第四部分中, 除了《Lua 脚本》一章的其中一节有涉及多机功能的内容之外, 其他章节都没有涉及多机功能的内容, 所以第四部分的大部分内容都可以在只阅读了本书第一部分和第二部分的情况下阅读。
图 1-1 对上面描述的阅读方法进行了总结。
![document/2015-09-13/55f4eb1dbb973](https://box.kancloud.cn/document_2015-09-13_55f4eb1dbb973.png)
## 行文规则
### 名字引用规则
在第一次引用 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 伪代码中通常会包含 `server` 和 `client` 两个全局变量: 其中 `server` 表示服务器状态(`redis.h/redisServer` 结构的实例), 而 `client` 则表示正在执行操作的客户端状态(`redis.h/redisClient` 结构的实例)。
## 配套网站
本书带有配套网站 [RedisBook.com](http://redisbook.com/) , 这个网站记录了本书的最新消息, 并且提供了附带详细注释的 Redis 源代码可供下载, 读者也可以通过这个网站查看和反馈本书的勘误, 或者发表与本书有关的问题、意见、以及建议。
- 介绍
- 前言
- 致谢
- 简介
- 第一部分:数据结构与对象
- 简单动态字符串
- SDS 的定义
- SDS 与 C 字符串的区别
- SDS API
- 重点回顾
- 参考资料
- 链表
- 链表和链表节点的实现
- 链表和链表节点的 API
- 重点回顾
- 字典
- 字典的实现
- 哈希算法
- 解决键冲突
- rehash
- 渐进式 rehash
- 字典 API
- 重点回顾
- 跳跃表
- 跳跃表的实现
- 跳跃表 API
- 重点回顾
- 整数集合
- 整数集合的实现
- 升级
- 升级的好处
- 降级
- 整数集合 API
- 重点回顾
- 压缩列表
- 压缩列表的构成
- 压缩列表节点的构成
- 连锁更新
- 压缩列表 API
- 重点回顾
- 对象
- 对象的类型与编码
- 字符串对象
- 列表对象
- 哈希对象
- 集合对象
- 有序集合对象
- 类型检查与命令多态
- 内存回收
- 对象共享
- 对象的空转时长
- 重点回顾
- 第二部分:单机数据库的实现
- 数据库
- 数据库键空间
- 重点回顾
- RDB 持久化
- RDB 文件结构
- 重点回顾
- AOF 持久化
- AOF 持久化的实现
- 重点回顾
- 事件
- 文件事件
- 重点回顾
- 参考资料
- 客户端
- 客户端属性
- 重点回顾
- 服务器
- 命令请求的执行过程
- 重点回顾
- 第三部分:多机数据库的实现
- 复制
- 旧版复制功能的实现
- 重点回顾
- Sentinel
- 启动并初始化 Sentinel
- 重点回顾
- 参考资料
- 集群
- 节点
- 重点回顾
- 第四部分:独立功能的实现
- 发布与订阅
- 频道的订阅与退订
- 重点回顾
- 参考资料
- 事务
- 事务的实现
- 重点回顾
- Lua 脚本
- 创建并修改 Lua 环境
- 重点回顾
- 排序
- SORT <key> 命令的实现
- 重点回顾
- 二进制位数组
- GETBIT 命令的实现
- 重点回顾
- 慢查询日志
- 慢查询记录的保存
- 慢查询日志的阅览和删除
- 添加新日志
- 重点回顾
- 监视器
- 成为监视器
- 向监视器发送命令信息
- 重点回顾
- 源码、相关资源和勘误