1. 前言:
- redis是一个基于内存是键值对数据库,但是并非把数据存入内存就高枕无忧了。
- 为了应对可能出现的进程中止,断电等意外情况,redis提供了持久化功能把数据持久化到硬盘。
2. RDB持久化
2.1. rdb文件的创建
rdb通过创建二进制数据文件进行文件的恢复和备份。
- SAVE命令
使用后redis阻塞所有命令。 - BGSAVE
BGSAVE 会启动一个子进程进行rdb备份。
总结:
-
SAVE和 BGSAVE都是调用 rdbSAVE 方法进行备份。
-
BGSAVE的时候BGREWRITEAOF操作会被延迟执行。
-
载入rdb文件的命令为rdbLoad。
-
服务器载入rdb文件的时候为阻塞状态。
2.2. 自动备份rdb
redis允许用户使用一些任务条件触发bgsave进行rdb备份。
redis通过saveprams添加savepram添加哎保存条件,只要条件有一个满足,就会执行rdb备份。
redis会每100毫秒遍历一次是否有条件满足。
# 添加条件,900秒内进行了一次修改
save 900 1
redis中通过redisSetver中:
- dirty:记录从上次rdbSave到现在修改次数
- lastsave: 上次执行保存的时间
2.3. rdb的文件结构
1. rdb文件
- REDIS: 开头的五个字节,用于标识rdb文件
- db_version: 版本号,字符串表示的整数
- datebases : 核心存储数据
- EOF: 结束符
- check_sum: 校验和
2. database
- SELECTDB: 1字节,标识着数据库数据
- db_number: 1/2/5字节,数据库编号
- key_value_pairs: 核心保存数据
3.key_value_pairs
- EXPIRETIME_MS: 1字节,字段标志符。
- ms: 8字节整数,unix时间戳,过期时间。
- type: value对象类型
- key:键值对key,字符串对象
- value:键值对value,根据type决定类型
2. AOF持久化
aop通过保存保存写命令记录数据库状态。
2.1. AOF 存储流程
- 当redis收到写命令是会把写命令追加到buf里,如使用
set KEY VALUE
- redis会使用processFileEvents定期把buf里数据追加到aof文件里。频率为每次loop(redis本质就是一个无限loop的进程)
- flushAppendOnlyFile默认的默认策略是everysec
策略 | appendfsync 选项的值 |
---|---|
always | 将 aof_buf 缓冲区中的所有内容写入 AOF 文件 |
everysec | 每秒将 aof_buf 缓冲区中的所有内容写入 AOF 文件,如果上次同步 AOF 文件的时间间隔超过了一秒钟,那么再次对 AOF 文件进行同步,并且这个同步操作是由一个线程专门负责执行的 |
no | 将 aof_buf 缓冲区中的所有内容写入 AOF 文件,但并不对 AOF 文件进行同步,同步操作由操作系统决定何时执行 |
为什么要有这几个策略?
- 在操作系统中,如果执行write把数据写入到硬盘的时候,操作系统并不会立马写入,而是保存到缓冲区。等到缓冲区满或者超过一定时间才写入。
- 这带来了额外的数据安全问题,redis提供了同步函数flushAppendOnlyFile,强制让操作系统把数据写入到硬盘。
- 这几种策略是选择什么时候强制把数据写入硬盘。不同的写入策略关乎到性能和安全的权衡。
2.2. AOF 的读取和优化
-
读取aof还原
aof通过伪客户端,一步一步执行写入命令,由于aof文件保存了100%的写入命令,理论上它要慢得多。事实上也确实,但是aof存在优化策略,把部分写入命令合并。 -
重写aof优化
如果能把这六个命令变成一个命令就可以大大寄生空间
PRUSH list “C”
PRUSH list “A”
PRUSH list “B”
PRUSH list “G”
PRUSH list “D”,"E"
# 合成后
PRUSH list "A","B","C","D","E"
是不是以为redis要遍历aof文件找相同的合并同类项了?
可惜并没有。redis的重写并非老实巴交的合并同类项,而是通过查询redis数据库数据项,生成一个当前状态的写入语句。redis甚至没有遍历旧的aof文件。
灵魂拷问:既然大概率重写,为什么要高缓冲区的那一套呢?
答:其实是一个空间和性能的综合考虑,而且aof 重写的概率并不高。
- aof的不阻塞重写
- aof通过子进程堆aof重写,能正常接受业务。
- aof会将新的写入命令写如重写缓冲区
- aof子进程完毕,请求父进程接管,父进程
- 把aof重写缓冲区内容追加到aof新文件里,然后原子地替换旧的aof文件