美文网首页
Redis - 持久化

Redis - 持久化

作者: Zeppelin421 | 来源:发表于2022-02-28 14:23 被阅读0次

Redis是内存数据库,宕机后数据会消失。
Redis重启后快速恢复数据,需要提供持久化机制

RDB

RDB(Redis DataBase)是Redis默认的存储方式,RDB是通过快照(snapshotting)完成的

触发方式

  • 符合自定义配置的快照规则
  • 执行 save 或者 bgsave 命令
  • 执行 flush 命令
  • 执行主从复制操作(第一次)

配置参数

# redis.conf
save <seconds> <change>

save "" # 不使用RDB存储

save 900 1     # 表示15分钟内至少1个key被更改则进行快照
save 300 10   # 表示5分钟内至少10个键值被更改则进行快照
save 60 1000 # 表示1分钟内至少1000个键值被更改则进行快照

TIPS:漏斗设计,提高性能

原理

  • Redis父进程首先判断当前是否在执行save命令,或者bgsave/bgrewriteaof的子进程,如果在执行直接返回
  • 父进程执行fork(调用OS函数复制主进程)操作创建子进程,这个复制过程中父进程是阻塞的,Redis不能执行来自客户端的任何命令
  • 父进程fork后,bgsave命令返回“Background saving started”信息并不再阻塞父进程,并可以响应其他命令
  • 子进程创建RDB文件,根据父进程内存快照生产临时快照文件,完成后对原有文件进行原子替换
  • 子进程发送信号给父进程表示完成,父进程更新统计信息
  • 父进程fork子进程后,继续工作

文件结构
"REDIS" RDB_VERSION AUX_FIELD_KEY_VALUE_PAIRS DB_NUM DB_DICT_SIZE EXPIRE_DICT_SIZE KEY_VALUE_PAIRS EOF CHECK_SUM

1、头部5字节固定位“REDIS”
2、4字节“RDB”版本号,当前为9,填充后0009
3、辅助字段,以key-value的形式

字段名 字段值 字段名 字段值
redis-ver 5.0.5 aof-preamble 是否开启AOF
redis-bits 64/32 repl-stream-db 主从复制
ctime 当前时间戳 repl-id 主从复制
used-mem 使用内存 repl-offset 主从复制

4、存储数据库号码
5、字典大小
6、过期key
7、主要数据,以key-value形式存储
8、结束标识
9、校验和,就是看文件是否损坏或者是否被修改

优缺点

  • 优点
    RDB是二进制压缩文件,占用空间小,便于传输(主从同步)
    主进程fork子进程,可以最大化redis性能,主进程不能太大,复制过程中主进程阻塞
  • 缺点
    不保证数据完整性,会丢失最后一次快照以后更改的所有数据

AOF

AOF(append only file)是Redis的另一种持久化方式。Redis默认情况下是不开启的。
开启AOF之后,Redis将所有对数据库进行过写入的命令(及其参数)(RESP)记录到AOF,以此达到记录数据库状态的目的。
当Redis重启后只要按照顺序回放这些命令就会恢复到原始状态
AOF会记录过程,RDB只管结果

配置

appendonly yes # 开启

# AOF文件的保存位置,和RDB文件的位置相同
dir ./

# 默认的文件名是appendonly.aof
appendfilename appendonly.aof

原理

AOP文件中存储的是Redis的命令,同步命令到AOF文件的整个过程可以分为三个阶段:

  • 命令传播
    服务器在收到请求后,它会根据协议文本的内容选择适当的命令函数,并将各个参数从字符串文本转化为Redis字符串对象(StringObject)。每当命令函数成功执行后,命令、命令的参数、命令的参数个数等信息发送到AOF程序中
  • 缓存追加
    AOF程序根据接收到的命令数据,将命令从字符串对象转换回原来的协议格式,然后将协议内容追加到服务器的AOF缓冲中(redisServer结构的aof_buf),aof_buf域则保存着所有等待写入到AOF文件的协议文本(RESP)
  • 文件写入或保存
    每当服务器常规任务函数被执行、或者事件处理器被执行时,flushAppendOnlyFile 函数都会被调用,这个函数执行以下两个工作
    • WRITE:根据条件将aof_buf中的缓存写入到AOF文件(内存中)
    • SAVE:根据条件调用 fsyncfdatasync 函数,将AOF文件保存到磁盘中

保存模式

// redis.conf
# appendfsync always
appendfsync everysec
# appendfsync no
  • 不保存(no)
    每次调用 flushAppendOnlyFile 函数,WRITE 都会被执行,SAVE 会被略过
    以下三种情况 SAVE 才会被执行(会引起 Redis 主进程阻塞)
    • Redis被关闭
    • AOF功能被关闭
    • 系统写缓存被刷新(可能是缓存已经被写满或者定期保存操作被执行)
  • 每秒保存一次(everysec)
    原则上每隔一秒就会执行一次,因为 SAVE 操作是由后台子线程(fork)调用的,所以不会引起服务器主进程阻塞
  • 每执行一个命令保存一次(always)
    每次执行完一个命令后,WRITE 和 SAVE 都会被执行。因为 SAVE 是由 Redis 主进程执行的,所以 SAVE 执行期间,主进程会阻塞不能接受命令请求

TIPS:WRITE 永远阻塞主进程,SAVE 只有在 everysec 模式下才不阻塞主进程

AOF重写

AOF记录数据的变化过程,执行命令越来越多,AOF记录越来越大,此时需要重写瘦身
Redis会在AOF体积变得过大时自动在后台(fork子进程)对AOF进行重写。重写后新的AOF文件包含了恢复当前数据集所需的最小命令集合。

set s1 11
set s1 22
set s1 33
优化后:
set s1 33

lpush list1 1 2 3
lpush list1 4 5 6
优化后:
lpush list1 1 2 3 4 5 6

Redis不希望AOF重写造成服务器无法处理请求,所以AOF重写程序在后台子进程中执行,这样的好处:

  • 子进程进行AOF重写期间,主进程可以继续处理命令请求
  • 子进程带有主进程的数据副本,使用子进程而不是线程,可以在避免锁的情况下,保证数据的安全性

同时子进程也引发新的问题:

子进程在进行AOF重写期间,主进程还需要继续处理命令,而新的命令可能对现有的数据进行修改,会导致当前数据和重写后的AOF文件中的数据不一致

解决方案:

Redis增加了一个AOF重写缓存,这个缓存在fork子进程之后开始启用,Redis主进程在接到新的命令之后,除了将这个写命令的协议内容追加到现有的AOF文件之外,还会追加到这个缓存中。当子进程完成AOF重写之后,它会向父进程发送一个完成信号,父进程在收到完成信号后,调用一个信号处理函数,并完成以下工作:
1、将AOF重写缓存中的内容全部写入到AOF文件中
2、对新的AOF文件进行改名,覆盖原有AOF文件


触发方式

# redis.conf
# 限制允许重写最小aof文件大小,也就是文件大小小于64mb的时候,不需要进行优化
auto-aof-rewrite-min-size 64mb
# 表示当前aof文件大小超过上一次aof文件大小的百分之多少的时候会进行重写,如果之前没有重写过,以启动时aof文件大小为准
auto-aof-rewrite-percentage 100

或者

127.0.0.1:6379> bgrewriteaof

混合持久化

Redis4.0开始支持 rdb 和 aof 的混合持久化。如果把混合持久化打开,aof rewrite 的时候就直接把 rdb 的内容写到 aof 文件开头
RDB的头 + AOF的身体 ------> appendonly.aof

# redis.conf
# 开启混合持久化
aof-use-rdb-preamble yes

AOF文件载入

AOF文件里面包含了重建数据库状态所需要的所有写入命令,所以服务器只要读入并重新执行一遍AOF文件里面保存的写命令,就可以还原服务器关闭之前的数据库状态

  1. 创建一个不带网络连接的伪客户端(fake client)
  2. 从AOF文件中分析并读取一条写命令
  3. 使用伪客户端执行被读出的写命令
  4. 一直执行步骤2和步骤3,直到AOF文件中的所有写命令都被处理完毕为止

对比

  • RDB存某个时刻的数据快照,采用二进制压缩存储;AOF存操作命令,采用文本存储(混合)
  • RDB性能高;AOF性能较低
  • RDB在配置触发状态会丢失最后一次快照以后更改的所有数据;AOF设置为每秒保存一次,则最多丢2秒的数据
  • Redis以主程序模式运行,RDB不会保存过期键值对数据,Redis以从服务器模式运行,RDB会保存过期键值对,当主服务器向从服务器同步时,再清空过期键值对;AOF写入文件时,对过期的key会追加一条del命令,当执行AOF重写时,会忽略过期key和del命令

相关文章

网友评论

      本文标题:Redis - 持久化

      本文链接:https://www.haomeiwen.com/subject/zmtlrrtx.html