Redis |持久化机制

127 阅读7分钟

Redis是一个内存数据库,为了保证数据的持久性,它提供了三种持久化方案:

  • RDB方式(默认)
  • AOF方式
  • 混合模式(4.0增加,5.0默认开启)

info persistence命令可以查看当前所有有关持久化的信息。

1 RDB

RDB文件是经过压缩的二进制文件RDBRedis默认采用的持久化方式。RDB是一种时间点(point-to-time)快照,适合数据备份及灾难恢复。

1.1 RDB文件创建

RDB有两种创建方式,rdb持久化,可以手动执行,也可以根据配置选项定期执行。

1.1.1 命令创建

  • SAVE:阻塞redis服务器进程,客户端请求被拒绝
  • BGSAVE:派生子进程创建,创建rdb文件
127.0.0.1:6379> SAVE
OK
127.0.0.1:6379> BGSAVE
Background saving started
127.0.0.1:6379>  LASTSAVE
(integer) 1611298430
  • BGSAVE期间,SAVE,BGSAVE被拒绝,防止产生竞争条件
  • BGSAVE执行时,BGREWRITEAOF命名被延迟到BGSAVE执行完后
  • BGREWRITEAOF执行时,BGSAVE被拒绝

1.1.2 自动创建

服务器配置

save 900 1  //900秒 内至少 1 个键被更改   
save 300 10   // 900秒 内至少 10 个键被更改   
save 60 1000    // 60 内至少 1000 个键被更改   

服务器在 x s内,对数据库执行了至少 y 次修改,三个条件任意一个满足,执行BGSAVE

如果需要关闭RDB的自动备份策略,可以使用

save ""  //```关闭RDB方式的持久化

1.2 RDB载入

载入(rdbload):服务器启动时自动执行,服务器期间一直处于阻塞状态。 AOF文件的更新频率通常比RDB'文件更新频率高,如果开启了AOF功能,优先使用AOF文件还原。

image.png

2 AOF

AOF,全称append only file持久化,通过保存Redis服务器所执行的写命令来记录数据库状态。

2.1 开启AOF持久化功能

修改redis.conf并重启

# no-关闭,yes-开启,默认no
appendonly yes
appendfilename appendonly.aof

也可以直接使用config命令

config set

2.2 AOF持久化的流程

2.2.1 命令追加append

AOF持久化功能打开时,服务器执行完一个写命令后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区末尾。

注意
如果命令追加时正在进行AOF重写,这些命令还会追加到重写缓冲区aof_rewrite_buffer

2.2.2 文件写入与同步

服务器的进程就是一个事件循环,循环中的文件事件负责接收客户端请求,发送命令回复;而时间时间则负责执行像serverCron这样需要定时运行的函数。

服务器处理文件事件时可能会执行写命令,使内容加到aof_buf缓冲区。服务器在结束一个事件循环前调用flushAppledOnlyFile函数,会把AOF缓冲区(aof_buf)中的数据写入内核缓冲区 ,由appendfsync选项值决定是否将内核缓冲区写入磁盘(AOF文件)。

appendfsync选项值策略:

  • always写入内核缓冲区并同步到AOF文件

  • everysec写入内核缓冲区,如果距离上次同步时间超过1s则同步(默认)

  • no:写入内核缓冲区,但不同步,何时同步由操作系统决定

appendfsync策略受配置项no-appendfsync-on-rewrite的影响,表示AOF文件重写期间是否禁止调用fsync。

  • no:是最安全的方式,但是要忍受阻塞的问题,默认是no
  • yes:数据只是写入了缓冲区,可能丢失数据

关于linux文件写入和同步
为了解决文件读写速度远远比不上CPU的问题,操作系统提供了延迟写(delayed write)机制来提高硬盘的I/O性能 。 用户调write函数写入文件时,操作系统将数据暂存在内存缓冲区,等缓冲区满或超过指定时限后才真正写入磁盘。 系统提供了fsyncfdatasync两个同步函数,立即写入磁盘,保证数据安全性。

2.3 AOF载入

第一步 创建一个不带网络连接的伪客户端
第二步 aof文件分析并取出一条写命令
第三步 伪客户端执行写命令
第四步 一直执行第二步 和 第三步,直到aof文件写命令被处理完。还原数据库状态

2.4 AOF重写

为了解决AOF文件体积膨胀的问题,redis通过AOF重写功能,创建一个新的AOF文件来替代现有的AOF文件。

image.png

重写既减少了AOF文件对磁盘空间的占用,又可以提高Redis重启时数据恢复的速度。如上图,旧文件中的6条命令等同于新文件中的1条命令。

2.4.1 重写的触发

(1)手动触发:直接调用bgrewriteaof命令,如果当时无子进程执行会立刻执行,否则安排在子进程结束后执行。

(2)自动触发: 由Redis的周期性方法serverCron检查在满足以下两个条件时触发:

  • 增长比例:
(aof_current_size - aof_base_size) / aof_base_size > auto-aof-rewrite-percentage
  • 文件大小
aof_current_size > auto-aof-rewrite-min-size
  • auto-aof-rewrite-percentage :代表当前AOF文件大小(aof_current_size)和上一次重写后AOF文件大小(aof_base_size)相比,增长的比例
  • auto-aof-rewrite-min-size:表示运行bgrewriteaof时AOF文件占用空间最小值,默认为64MB
  • aof_base_size : 初始化为当时aof文件的大小,Redis运行过程中,当AOF文件重写操作完成时,会对其进行更新
  • aof_current_size: serverCron执行时AOF文件的实时大小

2.4.2 重写的实现

重写的命令有两个:aof_rewritebgrewriteaof
使用aof_rewrite命令进行aof重写期间,无法处理客户端请求,所以,redis使用bgrewriteaof命令将重写放入子进程中,避免服务阻塞。

重写期间,进程还要继续处理命令请求,需要解决aof文件所保存的数据库状态和当前不一致

第一步 设置AOF重写缓冲区,在服务器创建子进程后开始用
第二步 当redis服务器执行一个写命令后,同时将写命令发送给AOF缓冲区AOF重写缓冲区AOF缓冲区内容会被定期写入同步到AOF文件,现有AOF文件的处理工作正常进行
第三步 子进程完成AOF重写后,向父进程发送一个信号,父进程接收信号后调用一个信号处理函数
第四步 服务器阻塞处理信号函数:
(1)将AOF重写缓冲区所有内容写入到新的AOF文件中,这时新AOF文件保存的数据库状态和当前数据库状态一致;
(2)对新的AOF文件改名,原子的覆盖现有的AOF文件,完成新旧两个AOF文件的替换。

信号处理函数执行完后,父进程继续正常接收命令,信号处理执行时会对服务器进程阻塞

image.png

3 混合模式

混合持久化是Redis 4.0才有的功能。

混合持久化同样也是通过bgrewriteaof完成的,不同的是,混合持久化时,fork出的子进程先将共享的内存副本以RDB方式写入AOF文件,再将重写缓冲区的增量命令以AOF方式写入到文件,写入完成后通知主进程更新统计信息,并将新的AOF文件替换旧的的AOF文件。

简单理解:新的AOF文件前半段是RDB格式的全量数据,后半段是AOF格式的增量数据

4 RDB和AOF

Redis提供了两种持久化的选择:RDB支持以特定的时间间隔为数据集生成时间点快照;AOF把Redis Server收到的每条写指令持久化到日志中,待Redis重启时通过重放命令恢复数据。

4.1 RDB和AOF区别

  • RDB是把键值对保存到RDB文件中,AOF是把服务器执行的SET命令保存到AOF文件中
  • AOF文件通常会比RDB文件大
  • RDB是Redis数据的内存快照,相比于AOF的命令重放有着更高的性能
  • RDB方式无法做到实时或秒级持久化(fork调用),AOF持久化有更好的实时性和安全性(appendfsync策略控制)

4.2 关于fork

fork是一个重量级操作,会对Redis造成阻塞。RDB快照AOF重写都需要调用fork。为了不影响Redis主进程响应,注意以下基地

  • 降低fork的频率,比如可以手动来触发RDB生成快照、与AOF重写;
  • 控制Redis最大使用内存,防止fork耗时过长;