文章目录
服务器
数据库
redis客户端都有自己的目标数据库,默认为0号数据库,使用select进行切换
struct redisServer{
int dbnum; //服务的数据库数量,由数据库配置database决定,默认16
redisDb *db; //保存服务器中所有数据库信息
saveparam *saveparams; //保存条件的数组 saveparam={seconds,changes}
}
struct redisClient{
redisDb *db; //记录客户端正在使用的数据库,指向redisServer.db数组
}
客户端的目标数据库为1号数据库
注意:谨慎处理多数据库程序,redis没有返回目标数据库的命令,建议显示切换数据库后,再执行其他操作。
键空间以及生存时间,过期时间
键空间详解
struct redisDb{
dict *dict; //dict字典保存了数据库中所有的键值对,称为键空间
}
redisDb保存了所有键空间,键空间和用户所见的数据库是直接对应的。
- 键空间的键就是redis数据库的键,每个键都是一个String对象
- 键空间的值就是redis数据库的值,每个值可以是五种基本对象
举例:所有的对象都嵌套了字符串对象
set message "hello"
rpush alphabet "a" "b" "c"
hset book name "redis"
hset book author "Carlson"
hset book publisher "Manning"
通过键空间(dict字段)实现的指令:flushdb,dbsize,exists,rename,keys,
设置键的生存时间
- 设置键的生存时间
所有设置键生存时间的命令,最后都转化为pexpireat
## 设置key的生存时间为5秒
expire key 5
## 设置key的生存时间为5毫秒
pexpire key 5
## 设置key的生存截止时间
expireat key UNIX时间戳
## 设置key=true,生存时间为5秒
set key true ex 5 nx
## 返回这个键的剩余生命时间
ttl key
- 保存键的生存时间-过期字典
struct redisDb{
dict *dict; //dict字典保存了数据库中所有的键值对,称为键空间
dict *expire; //expire字段保存了数据库键的过期时间,称为过期字典
}
键字典+过期字典
移除键的生存时间
persist key 移除生存时间
计算键的生存时间,判定过期键
TTL key
- 首先检查key是否存在过期字典,存在获取过期时间
- 检查UNIX时间戳是否大于key过期时间,如果大于,则过期
过期键的三种删除策略
- 定时删除:设置过期时间同时,创建一个定时器
优点:对内存友好,尽可能快的删除
缺点:对cpu不友好,若过期键过多,会占用cpu。定时器事件用到时间事件 - 惰性删除(被动删除):放任过期键不管,当获取键时expireIfNeeded函数检查是否过期,过期就删除该键
优点:对cpu友好,只会操作键做过期检查,而不会删除其他无关过期键
缺点:对内不能不友好,过期键占用内存不释放,类似内存泄漏 - 定期删除:每过一段时间,程序对数据库检查,然后删除过期键
redis周期性serverCorn函数执行时,activeExpireCycle函数就会被调用
函数从一定数量的db,取出一定数量的随机键进行检查,并删除过期键
current_db会记录函数检查进度,保证下次执行下一个数据库
若所有数据库都执行完,current_db重置为0,再开始新一轮检查。
redis删除过期键的策略
- redis服务器使用定期删除和惰性删除两种策略,惰性删除策略只在碰到过期键才会进行删除,定期删除策略则每隔一段时间主动删除过期键
- 执行bgsave命令创建RDB文件时,新的RDB文件不会包含过期的键;载入RDB由于主从同步不会造成影响
- 执行bgrewriteaof重写AOF文件时,新的AOF文件不会包含过期键
- 主服务器删除过期后,会向从服务器发送一条del命令
- 从服务器发现过期键不会自己删除,而是等待主服务器发del命令。这种中心化的删除策略保证主从一致性
- redis命令对数据库修改后,服务器会根据配置向客户端发送通知。
RDB持久化
RDB持久化是将redis的内存数据保存到磁盘里面来进行持久化的。
RDB持久化的实现
- 手动执行,也可以根据配置定期执行RDB持久化
save命令会阻塞redis服务器进程,直到RDB文件创建完毕为止,导致服务器不能处理任何请求。
bgsave命令会生成一个子进程,子进程负责创建RDB文件,父进程继续处理命令请求 - 何时载入RDB文件
服务器启动时会自动检测到RDB文件,然后自动载入。
由于AOF文件更新频率比较高,如果服务器开启AOF持久化功能,服务器会优先使用AOF文件恢复数据。 - bgsave执行时,载入时的限制
bgsave执行时拒绝执行bgsave,save命令,但是会延迟执行bgrewriteaof命令,反过来则拒绝执行
服务器载入RDB期间,会一直处于阻塞状态,直到载入完成
自动间隔保存
##服务器在60秒内对数据库至少做了10000次修改
##配置文件or传入启动参数
save 900 1
save 300 10
save 60 10000
- 服务器会根据save选项设置redisServer的saveparams中seconds和changes
- 当服务器成功执行数据库修改命令后,会累加dirty计数器
- serverCorn默认每隔100毫秒就执行一次,检查saveparams中的条件是否满足,满足则执行bgsave并记录lastsave属性
RDB文件结构
REDIS5字节字符:表示此文件为RDB文件
db_version:记录rdb文件的版本号
databases:保存多个数据库的数据
EOF:标志着rdb文件正文的结束
check_sum:效验和,检查RDB文件是否出错
SELECTDB:标识下一个字节是数据库号码
db_number:数据库号码
key_value_pairs:保存数据库所有键值对
type:保存键的底层数据结构
EXPIRETIME_MS:表示下一个字节为过期时间
- 字符串对象
- 列表对象
- 集合对象
- 字典对象
- 有序列表
RDB文件总结
- 用于保存和还远redis数据库中所有键值对数据
- save命令服务器进程直接保存,阻塞服务器,bgsave由子进程保存,不会则色服务器
- 由save选项设置保存条件,当任意条件满足时,服务器自动执行bgsave命令
- rdb文件是一个经过压缩的二进制文件,对于不同的键值对,使用不同方式来保存它们。
AOF持久化
AOF是通过记录写命令来对redis进行持久化的。
例子:
set msg "hello"
sadd fruit apple banana cherry
rpush numbers 1 1 2
RDB持久化保存:msg,fruit,numbers这三个键值对
AOF持久化保存:保存set,sadd,rpush这三个命令
AOF持久化的实现
命令追加——>文件写入与同步
- 命令追加
服务器执行写命令后,将写命令追加到服务器aof_buf缓冲区的末尾 - 文件写入与同步
redis的服务器进程就是一个事件循环:文件事件负责接收命令请求,向客户端回复。时间事件执行serverCorn定时函数等
当写命令追加到aof_buf中后,通过appendfsync不同值产生不同行为。
若等于always,则在每个事件循环将aof-bug所有数据都写入并同步到AOF文件
若等于everysec,则在每个事件循环将aof-buf写入aof文件缓冲区,然后每隔1秒同步到AOF文件;
若等于no,在每个事件循环将aof-buf写入aof文件缓冲区,何时同步由os决定
解决写入数据带来的安全问题:
使用fsync和fdatasync手动 将数据从缓冲区同步到磁盘,确保写入数据的安全性
AOF数据恢复
创建伪客户端,从AOF文件循环读出写命令让伪客户端执行,直到所有写命令执行完毕为止。
解决AOF文件文件体积膨胀问题
为了解决AOF文件体积膨胀问题:例如服务器对list键执行了100次rpush操作,挤压保存100个指令。
AOF创建新AOF文件替代现有AOF文件,并保证不会包含任何冗余命令,达到AOF文件瘦身的目的。
执行bgrewriteaof步骤:
- 创建新的AOF文件
- 遍历redis数据库的所有键,然后根据键的类型进行重写
- 为了避免输入缓冲区溢出,在操作集合类键类型时,会先检查是否超过REWRITE_ITEM_PER_CMD
- 服务器进程除了执行客户端发来的命令外,还要将执行后的写命令追加到AOF缓冲区,AOF重写缓冲区
- 子进程完成重写工作后,向父进程发信号,然后父进程将AOF重写缓冲区中的内容写入新AOF文件中,然后通过改名替换现有AOF文件
事件机制
redis服务器是一个事件驱动程序。基于Reactor模式开发了网络事件处理器(文件时间处理器)
文件事件:redis服务器通过套接字与客户端进行连接,文件事件就是对套接字操作的抽象,服务器通过监听并处理事件完成一些列网络通信操作。
时间事件:时间事件就是对定时操纵的抽象
文件事件
文件事件处理器使用I/O多路复用程序同时监听多个套接字,并根据套接字执行的任务,为套接字关联不同的事件处理器。
文件事件处理器={套接字,IO多路复用程序,文件事件分配器,事件处理器}
IO多路复用程序总是将发生事件的套接字 放到一个队列中,然后依序 传递到文件事件分派器。
事件的类型
IO多路复用程序可监听多个套接字的readable和writable事件
客户端执行write,close操作时,套接字产生ae_readable事件
客户端执行read操作时,套接字产生ae-writable事件
若一个套接字同时产生了这两种事件,那么文件事件分派器优先处理ae_readable事件,在处理ae-writable事件。
文件事件处理器
程序会将文件事件处理器 与 服务器监听套接字的ae_readable事件关联起来
- 连接应答处理器:对连接服务器监听套接字的客户端进行应答
- 命令请求处理器:
- 命令回复处理器
客户端向服务器发送连接请求,服务器执行连接应答处理器
客户端向服务器发送命令请求,服务器执行命令请求处理器
服务器产生命令回复,服务器执行命令恢复处理器。