1.RDB持久化
redis是内存数据库它将自己的数据库状态存储在内存里,如果系统断电怎么办,进程退出怎么办,数据就需要保存,进行持久化操作,可以设置手动执行或者定期执行,保存到RDB文件中.
RDB文件是一个经过压缩的二进制文件,序列化生成后可以保存状态,
RDB文件创建和载入:
SAVE 创建:直接阻塞服务器进程,创建文件
BGSAVE:先派生出一个子进程,由子进程创建RDB
redis的文件载入工作是在服务器启动时自动执行的,所以rdis并没有专门的载入指令,当RDB文件存在时就自动载入
如果开启了AOF 优先载入AOF还原数据库状态,当AOF关闭时才可以使用RDB(RDB要完,凸( •̀_•́ )凸).
当BGSAVE创建子进程执行save时不是阻塞进程的,还可以接受操作,当遇到SAVE,BGSAVE时直接拒绝,遇到BGREWAITEAOF时,bgsave在前时,bgrewaiteaof会延迟到bg执行完,反之bg会被拒绝.
接下来就是redis的自动保存了
通过设置save条件当满足时 就会调用bgsave执行
例如: save 900 1 在900秒内执行至少一次修改就会调用BGSAVE;
redis的默认设置项
save 900 1
save 300 10
save 60 10000 三个条件满足一个即可
这些在saveparam *saveparams;{time_t seconds; int changes;}
数据库还保存了一个dirty计数器(距离上次成功执行RDB 数据库进行了多少次修改)以及一个lastsave属性(unix时间戳,记录上次成功RDB的时间):
检查save条件是否满足 使用serverCron函数 默认每隔100毫秒执行一次,
RDB文件结构:
开头是REDIS为五个字节,检查是否是RDB文件
db_version为4个字节,是字符串表示的整数,记录RDB文件的版本号
databases包含多个数据库及数据库包含的键值对数据
EOF常量长度为11字节表示正文结束;
check_sum 8字节整数 校验和
databases部分解析:
对于0 3数据库非空来说,每个数据库都保存着以下结构
SELECTDB:常量 长1字节.当程序遇到这个值得时候,知道这接下来就是数据库号码db_number 调用select
key_value_pairs部分保存了数据库中的所有键值对数据,如果带有过期时间也会和键值对保存在一起,
结构: type key value
key总是一个字符串对象,值根据type使用不同value的结构
分析RDB文件:
使用od -c 文件名.rdb 打印rdb文件
使用set MSG "HELLO"
2.AOF持久化
aof是通过保存redis数据服务器所执行的写命令来记录数据库状态的
rdb是保存键值信息,而aof保存则是将服务器执行的set 等命令保存到aof中
被写入的aof文件的所有的命令是以redis的命令请求协议保存的纯文本的,
AOF的实现:
在redisServer结构中有 sds aof_buf;//aof缓冲区;
当执行写时就同时向aof_buf中追加到其末尾
如何做到这种写入与同步呢?(将操作写入到aof文件中)
上文提到过自动判断save条件的 serverCron函数(就是一个定时运行的),所以在每次结束一个事件循环之前,都会调用flushAppendOnlyFile函数 考虑是否将aof_buf写入aof文件
aof文件载入和还原:就执行aof中的命令创建一个伪客户端,模拟执行写命令
aof重写:(有些键的值被写了多次,只需要保存最后一次的状态就行)减少文件体积和执行次数;
通过该功能redis可以创建一个新的AOF文件来代替现有的AOF文件,新旧两个AOF文件所保存的数据库状态相同,
这个新的AOF是通过对读取数据库当前的数据库状态来实现的,并不是去读取原来旧的AOF文件,对于执行了多次的list 加入文件与其保存多次list写操作,还不如直接从数据库直接读当前的list
可以使用后台执行fork一个子线程进行执行写操作写入aof重写缓存区,当redis执行完一个写命令时,将这个命令发送给aof缓存区和aof重写缓存区,
就是说在子进程aof执行重写时,服务器会继续执行客户端命令,并将命令追加到两个区.
完成重写后就向父进程发送信号,并将aof重写缓冲去的数据写入到新的aof文件,对新aof改名,原子性覆盖旧的aof文件
.
发表回复