Redis的持久化


Redis的持久化

众所周知,Redis作为一个键值对内存数据库(NoSQL),数据都存储在内存当中,在处理客户端请求时,所有操作都在内存当中进行。

为了避免内存中数据丢失,Redis提供了对持久化的支持,我们可以选择不同的方式将数据从内存中保存到硬盘当中,使数据可以持久化保存。

redis持久化有两种方式:RDB & AOF。一个是快照的方式,一个是类似日志追加的方式。

RDB

RDB是一种快照存储持久化方式,会生成RDB文件,该文件是一个压缩过的二进制文件,具体就是将Redis某一时刻的内存数据保存到硬盘的文件当中,默认保存的文件名为dump.rdb,而在Redis服务器启动时,会重新加载dump.rdb文件的数据到内存当中恢复数据。

# 设置 dump 的文件名
dbfilename dump.rdb

# 工作目录
# 例如上面的 dbfilename 只指定了文件名,
# 但是它会写入到这个目录下。这个配置项一定是个目录,而不能是文件名。
dir ./

触发快照的时机

  • 执行savebgsave命令
  • 配置文件设置save <seconds> <changes>规则,自动间隔性执行bgsave命令
  • 主从复制时,从库全量复制同步主库数据,主库会执行bgsave
  • 执行flushall命令清空服务器数据
  • 执行shutdown命令关闭Redis时,会执行save命令

开启RDB持久化方式

save命令

以同步的方式进行持久化方式

> save

在进行持久化此期间,使用save命令会阻塞Redis服务器进程,服务器进程在RDB文件创建完成之前是不能处理任何的命令请求

save命令持久化

bgsave

与save命令不同,bgsave命令是一个异步操作。

>&nbsp;bgsave

basave命令会fork一个子进程,然后该子进程会负责创建RDB文件,而服务器进程会继续处理命令请求

fork()是由操作系统提供的函数,作用是创建当前进程的一个副本作为子进程

bgsave

fork一个子进程,子进程会把数据集先写入临时文件,写入成功之后,再替换之前的RDB文件,用二进制压缩存储,这样可以保证RDB文件始终存储的是完整的持久化内容

save与bgsave对比

命令 save bgsave
IO类型 同步 异步
是否阻塞 是(阻塞发生在fork)
复杂度 O(n) O(n)
优点 不会额外消耗内存 不阻塞客户端命令
缺点 阻塞客户端命令 需要fork,消耗内存

配置自动触发

除了通过客户端发送命令外,还有一种方式,就是在Redis配置文件(redis.conf)中的save指定到达触发RDB持久化的条件就开启数据同步。

在redis.conf中配置如下选项

#&nbsp;900s内至少达到一条写命令
save&nbsp;900&nbsp;1
#&nbsp;300s内至少达至10条写命令
save&nbsp;300&nbsp;10
#&nbsp;60s内至少达到10000条写命令
save&nbsp;60&nbsp;10000

之后在启动服务器时加载配置文件。

#&nbsp;启动服务器加载配置文件
redis-server&nbsp;redis.conf

这种通过服务器配置文件触发RDB的方式,与bgsave命令类似,达到触发条件时,会forks一个子进程进行数据同步,不过最好不要通过这方式来触发RDB持久化,因为设置触发的时间太短,则容易频繁写入rdb文件,影响服务器性能,时间设置太长则会造成数据丢失

更多配置

# 是否压缩rdb文件
rdbcompression yes

# rdb文件的名称
dbfilename redis-6379.rdb

# rdb文件保存目录
dir ~/redis/

AOF

除了RDB持久化,Redis还提供了AOF(Append Only File)持久化功能,AOF持久化会把被执行的写命令写到AOF文件的末尾,记录数据的变化。默认情况下,Redis是没有开启AOF持久化的,开启后,每执行一条更改Redis数据的命令,都会把该命令追加到AOF文件中,这是会降低Redis的性能,但大部分情况下这个影响是能够接受的,另外使用较快的硬盘可以提高AOF的性能。

AOF方式

开启AOF持久化方式

Redis默认不开启AOF持久化方式,我们可以在配置文件中开启并进行更加详细的配置,如下面的redis.conf文件:

#&nbsp;开启aof机制
appendonly&nbsp;yes

#&nbsp;aof文件名
appendfilename&nbsp;"appendonly.aof"

#&nbsp;同步写入策略
# always 表示每个写操作都保存到aof文件中,这种策略很安全,但是每个写请注都有IO操作,所以也很慢。
# everysec (默认策略)每秒写入一次aof文件,因此,最多可能会丢失1s的数据。
# no  由系统决定什么时候写入aof文件
appendfsync&nbsp;always

#&nbsp;默认不重写aof文件
no-appendfsync-on-rewrite&nbsp;no

#&nbsp;保存目录
dir&nbsp;~/redis/

关于AOF的同步策略是涉及到操作系统的write函数和fsync函数的,在《Redis设计与实现》中是这样说明的。

为了提高文件写入效率,在现代操作系统中,当用户调用write函数,将一些数据写入文件时,操作系统通常会将数据暂存到一个内存缓冲区里,当缓冲区的空间被填满或超过了指定时限后,才真正将缓冲区的数据写入到磁盘里。

这样的操作虽然提高了效率,但也为数据写入带来了安全问题:如果计算机停机,内存缓冲区中的数据会丢失。为此,系统提供了fsyncfdatasync同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保写入数据的安全性。

从上面的介绍我们知道,我们写入的数据,操作系统并不一定会马上同步到磁盘,所以Redis才提供了appendfsync的选项配置。当该选项时为always时,数据安全性是最高的,但是会对磁盘进行大量的写入,Redis处理命令的速度会受到磁盘性能的限制;appendfsync everysec选项则兼顾了数据安全和写入性能,以每秒一次的频率同步AOF文件,即便出现系统崩溃,最多只会丢失一秒内产生的数据;如果是appendfsync no选项,Redis不会对AOF文件执行同步操作,而是有操作系统决定何时同步,不会对Redis的性能带来影响,但假如系统崩溃,可能会丢失不定数量的数据。

命令 always everysec no
优点 不丢失数据 每秒1次fsync 不用管
缺点 IO开销大 丢1秒数据 不可控

AOF文件重写

AOF将客户端的每一个写操作都追加到aof文件末尾,比如对一个key多次执行incr命令,这时候,aof保存每一次命令到aof文件中,aof文件会变得非常大。

incr&nbsp;num&nbsp;1
incr&nbsp;num&nbsp;2
incr&nbsp;num&nbsp;3
incr&nbsp;num&nbsp;4
incr&nbsp;num&nbsp;5
incr&nbsp;num&nbsp;6
...
incr&nbsp;num&nbsp;100000

aof文件太大,加载aof文件恢复数据时,就会非常慢,为了解决这个问题,Redis支持aof文件重写,通过重写aof,可以生成一个恢复当前数据的最少命令集(简单来说,就是减少AOF文件的冗余操作,精简AOF文件的体积),比如上面的例子中那么多条命令,可以重写为:

set num 100000

值得注意的是:

  • AOF文件重写并不需要对现有的AOF文件进行任何读取、分享和写入操作,而是通过读取服务器当前的数据库状态来实现的
  • aof文件是一个二进制文件,并不是像上面的例子一样,直接保存每个命令,而使用Redis自己的格式,上面只是方便演示。

两种重写方式

通过在redis.conf配置文件中的选项no-appendfsync-on-rewrite可以设置是否开启重写,这种方式会在每次fsync时都重写,影响服务器性以,因此默认值为no,不推荐使用。

#&nbsp;默认不重写aof文件
no-appendfsync-on-rewrite&nbsp;no

手动触发

客户端向服务器发送bgrewriteaof命令,也可以让服务器进行AOF重写。

# 让服务器异步重写追加aof文件命令
> bgrewriteaof

AOF重写方式也是异步操作,即如果要写入aof文件,则Redis主进程会forks一个子进程来处理,如下所示:

执行流程

  • 重写会有大量的写入操作,所以服务器进程会fork一个子进程来创建一个新的AOF文件
  • 在重写期间,服务器进程继续处理命令请求,如果有写入的命令,追加到aof_buf的同时,还会追加到aof_rewrite_bufAOF重写缓冲区
  • 当子进程完成重写之后,会给父进程一个信号,然后父进程会把AOF重写缓冲区的内容写进新的AOF临时文件中,再对新的AOF文件改名完成替换,这样可以保证新的AOF文件与当前数据库数据的一致性

自动触发

自动触发会根据auto-aof-rewrite-percentageauto-aof-rewrite-min-size 64mb配置来自动执行bgrewriteaof命令

# 表示当AOF文件的体积大于64MB,且AOF文件的体积比上一次重写后的体积大了一倍(100%)时,会执行`bgrewriteaof`命令
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

AOF文件损坏

在写入aof日志文件时,如果Redis服务器宕机,则aof日志文件文件会出格式错误,在重启Redis服务器时,Redis服务器会拒绝载入这个aof文件,可以通过以下步骤修复aof并恢复数据。

1、备份现在aof文件,以防万一。

2、使用redis-check-aof命令修复aof文件,该命令格式如下:

# 修复aof日志文件
$ redis-check-aof -fix file.aof

3、重启Redis服务器,加载已经修复的aof文件,恢复数据。

RDB 与 AOF 对比

命令 RDB AOF
启动优先级
体积
恢复速度
数据安全性 会丢失数据 策略决定
轻重量级

当RDB与AOF两种方式都开启时,Redis会优先使用AOF日志来恢复数据,因为AOF保存的文件比RDB文件更完整。

数据恢复

Redis4.0开始支持RDB和AOF的混合持久化(可以通过配置项 aof-use-rdb-preamble 开启)

  • 如果是redis进程挂掉,那么重启redis进程即可,直接基于AOF日志文件恢复数据
  • 如果是redis进程所在机器挂掉,那么重启机器后,尝试重启redis进程,尝试直接基于AOF日志文件进行数据恢复,如果AOF文件破损,那么用redis-check-aof fix命令修复
  • 如果没有AOF文件,会去加载RDB文件
  • 如果redis当前最新的AOF和RDB文件出现了丢失/损坏,那么可以尝试基于该机器上当前的某个最新的RDB数据副本进行数据恢复

小结

其实,如果只是单纯把Redis作为缓存服务器,那么可以完全不用考虑持久化,但是,在如今的大多数服务器架构中,Redis的单单只是扮演一个缓存服务器的角色,还可以作为数据库,保存我们的业务数据,此时,我们则需要好好了解有关Redis持久化策略的区别与选择。

参考资料

10分钟彻底理解Redis的持久化机制:RDB和AOF

Redis持久化机制:RDB和AOF

redis官方文档


文章作者: 银色回廊
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 银色回廊 !
评论
  目录