《Redis设计与实现》笔记
本书介绍了以下内容:
字符串(string)、散列(hash)、列表(list)、集合(set)和有序集合(sorted set)这五种类型的键的底层实现数据结构。
Redis 的对象处理机制以及数据库的实现原理。
事务实现原理。
订阅与发布实现原理。
Lua 脚本功能的实现原理。
SORT 命令的实现原理。
BITOP 、 BITCOUNT 等二进制位处理命令的实现原理。
慢查询日志的实现原理。
RDB 持久化和 AOF 持久化的实现原理。
Redis 事件处理器的实现原理。
Redis 服务器和客户端的实现原理。
复制(replication)、Sentinel 和集群(cluster)这三个多机功能的实现原理。
简单动态字符串
字符串(String)使用了一种称为简单动态字符串(Simple Dynamic String)的抽象数据类型,以空字符结尾,len + free + 1 = buf.length。
'''
struct sdshdr {
// buf 中已占用空间的长度
int len;
// buf 中剩余可用空间的长度
int free;
// 数据空间
char buf[];
};
'''
与C语言字符串的区别:
- O(1) 时间复杂度获取字符串长度
- 避免缓冲区溢出:拼接前进行长度检查
- 减少内存分配次数
- 空间预分配:newlen = (len+addlen); newlen = newlen + min(newlen, SDS_MAX_PREALLOC);
- 惰性空间释放
- 二进制安全:C语言字符串中不能包含空字符串(因此不能保存像图片、音频、视频、压缩文件这样的二进制数据),否则被判为结尾,而SDS用len判定
- 兼容部分C语言字符串函数
链表
列表键的底层实现结构之一是双向链表(也可能是压缩列表)。当列表键包含了许多元素,或者元素是比较长的字符串的时候,就会用到链表作为列表键的底层实现。
字典
字典,键值对,Redis数据库的存储就是用的hash索引,也是hash键的底层实现之一。

字典有2个哈希表,哈希表有一个dictEntry数组,dictEntry 哈希节点包含键、值、next。
- 哈希算法:index = hashFunc(key) & sizemask,采用高速的murmurhash2算法
- 键冲突解决:采用链地址法,插到头部(O(1))
- rehash:
- 装载因子=键值对/哈希表大小,0.1、1、5时
- 申请空间:扩容——2*x的最小2的n次方;收缩——x的最小2的n次方
- 渐进式rehash到 ht[1]上,对字典进行增删改查的时候进行一步rehash、将ht[0] rehashidx位置的数据迁移到ht[1]上,直到完成
跳表
平均O(logN),最坏O(N),支持顺序遍历查找。有序集合元素较多或是元素成员是比较长的字符串时就会使用跳表。

分值可以相同,成员对象必须唯一,跨度用来计算排位。
整数集合(intset)
保持升序、不重复的一个整数数组。当一个集合只包含整数值元素,并且这个集合的元素数量不多时,Redis就会使用整数集合作为集合键的底层实现。
升级:int32—>int64,重新分配数组空间。不支持降级。
压缩列表(ziplist)
list(元素少,小整数或短字符串时) 和 hash 的底层实现之一。
连锁更新:插入、删除最坏情况下N次空间重分配,每次最坏O(N),总共O(N^2)。但这个条件较苛刻,平均O(N)。
对象
字符串(string)、散列(hash)、列表(list)、集合(set)和有序集合(sorted set),Redis使用对象来表示数据库中的键和值,实现了基于引用计数的内存回收机制。
对象的类型(5种)和编码(底层实现)。
9.数据库
数据库主要由dict和expires两个字典构成,其中dict负责保存键值对,expires负责保存键的过期时间。服务器会自动删除生存时间为0的键。
10.RDB持久化
RDB持久化可以将Redis在内存中的数据库状态保存到磁盘里面,避免数据意外丢失。RDB可以手动执行,也可以定期执行。可以将某个时间点上的数据库状态保存到RDB文件中,通过该文件也可以还原数据库状态。
RDB创建和载入:SAVE(阻塞完成)和BGSAVE(子进程完成)。服务器启动时载入RDB文件、AOF文件状态还原。
自动间隔保存:svae 300 10,300秒内对数据库至少进行了10次修改。
11.AOF持久化
AOF(append only file)持久化:通过保存Redis服务器所执行的写命令来记录数据库状态。
实现:命令追加(append)、文件写入、文件同步(设置缓冲区写入选项)
AOF重写:创建一个新的AOF文件(用最少的命令去得到现在的数据库状态)来替代现有的AOF文件。
17.集群
集群包括多个节点,整个集群的数据库分为多个槽(分片保存数据库中的键值对)。每个节点都会记录哪些槽指派给了自己,哪些槽指派给了其他节点,用于执行命令、重新分片等。
18.发布和订阅
分为频道(weibo.hottag.star)和模式(weibo.hottag.*)。频道订阅信息由dict<channelName, linkedlist>存储,模式订阅信息存储在一条链表上。
19.事务
MULTI、EXEC。Redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会被执行。
WATCH命令:乐观锁,监视任意数量的数据库键,在EXEC执行时,检查被监视的键是否至少有一个被修改过,如果是,服务器将拒绝执行事务。

浙公网安备 33010602011771号