Redis的内部结构如下图所示:
各功能模块说明如下:
File Event: 处理文件事件(在多个客户端中实现多路复用,接受它们发来的命令请求(读事件),并将命令的执行结果返回给客户端(写事件))
Time Event: 时间事件(更新统计信息,清理过期数据,附属节点同步,定期持久化等)
AOF: 命令日志的数据持久化
RDB:实际的数据持久化
Lua Environment : Lua 脚本的运行环境. 为了让 Lua 环境符合 Redis 脚本功能的需求, Redis 对 Lua 环境进行了一系列的修改, 包括添加函数库、更换随机函数、保护全局变量, 等等
Command table(命令表):在执行命令时,根据字符来查找相应命令的实现函数。
Share Objects(对象共享):
主要存储常见的值:a.各种命令常见的返回值,例如返回值OK、ERROR、WRONGTYPE等字符;b. 小于 redis.h/REDIS_SHARED_INTEGERS (默认1000)的所有整数。通过预分配的一些常见的值对象,并在多个数据结构之间共享对象,程序避免了重复分配的麻烦。也就是说,这些常见的值在内存中只有一份。
Databases:
Redis数据库是真正存储数据的地方。当然,数据库本身也是存储在内存中的。
Databased的数据结构伪代码如下:
<span style="font-family:Microsoft YaHei;font-size:18px;">typedef struct redisDb { // 保存着数据库以整数表示的号码 int id; // 保存着数据库中的所有键值对数据 // 这个属性也被称为键空间(key space) dict *dict; // 保存着键的过期信息 dict *expires; // 实现列表阻塞原语,如 BLPOP // 在列表类型一章有详细的讨论 dict *blocking_keys; dict *ready_keys; // 用于实现 WATCH 命令 // 在事务章节有详细的讨论 dict *watched_keys; } redisDb; </span>
一个数据库,在内存中的数据结构如下图所示:
Database的内容要点包括:
- 数据库主要由 dict 和 expires 两个字典构成,其中 dict 保存键值对,而 expires 则保存键的过期时间。
- 数据库的键总是一个字符串对象,而值可以是任意一种 Redis 数据类型,包括字符串、哈希、集合、列表和有序集。
- expires 的某个键和 dict 的某个键共同指向同一个字符串对象,而 expires键的值则是该键以毫秒计算的 UNIX 过期时间戳。
- Redis 使用惰性删除和定期删除两种策略来删除过期的键。
- 更新后的 RDB 文件和重写后的 AOF 文件都不会保留已经过期的键。
- 当一个过期键被删除之后,程序会追加一条新的 DEL 命令到现有 AOF 文件末尾。
- 当主节点删除一个过期键之后,它会显式地发送一条 DEL 命令到所有附属节点。
- 附属节点即使发现过期键,也不会自作主张地删除它,而是等待主节点发来 DEL 命令,这样可以保证主节点和附属节点的数据总是一致的。
数据库的dict 字典和expires 字典的扩展策略和普通字典一样。它们的收缩策略是:当节点的填充百分比不足 10% 时,将可用节点数量减少至大于等于当前已用节点数量。