Redis数据持久化

Redis作为一个内存数据库,数据是以内存为载体存储的,即断电即失(一旦Redis服务器进程退出,服务器中的数据也会消失)。为了解决这个问题,Redis提供了持久化机制,也就是把内存中的数据保存到磁盘当中,避免数据意外丢失

Redis提供了两种持久化方案:RDB持久化AOF持久化,一个是快照的方式,一个是类似日志追加、历史记录的方式

一、RDB(Redis DataBase)

RDB是快照持久化,即通过快照SnapShot的方式,在指定的时间间隔内将内存中的数据集快照写入磁盘。在创建快照之后,用户可以备份该快照,可以将快照复制到其他服务器以创建相同数据的服务器副本,或者在重启服务器后恢复数据。RDB是Redis默认的持久化方式

RDB持久化会生成rdb文件,该文件是一个压缩过的二进制文件,可以通过该文件还原快照时的数据库状态,即生成该rdb文件时的服务器数据。rdb文件默认为当前工作目录下的dump.rdb,可以根据配置文件redis.conf中SNAPSHOTTING部分的dbfilenamedir设置rdb的文件名和文件位置。默认其实可以不需要改动。只要dump.rdb文件在redis的启动目录下,redis启动的时候就会自动检查dump.rdb恢复数据。

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

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

获取redis安装目录

127.0.0.1:6379> config get dir
1) "dir"
2) "/usr/local/bin" #如果在这个目录下存在dump.rdb文件,启动redis就会自动恢复数据

1、快照触发时机:

  • 执行savebgsave命令
  • 配置文件中save <seconds> <changes>规则,自动间隔性执行bgsave命令,如下图

image

表示在seconds秒内,至少有changes次变化,就会自动触发gbsave命令

  • 主从复制时,从库全量复制同步主库数据,主库会执行bgsave
  • 执行flushall命令清空服务器数据
  • 执行shutdown命令关闭Redis时,默认会执行save命令(可以手动shutdown nosave就不执行save命令)

2、save和bgsave命令:

执行savebgsave命令,可以手动触发快照,生成rdb文件,两者的区别如下

使用save命令会阻塞Redis服务器进程,服务器进程在rdb文件创建完成之前是不能处理任何的命令请求

127.0.0.1:6379> save
OK
复制代码

而使用bgsave命令不同的是,bgsave命令会fork一个子进程,然后该子进程会负责创建rdb文件,而服务器进程会继续处理命令请求。

image

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

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

【补充】

在生产环境中,通常我们会将dump.rdb文件进行备份。

3、优缺点

优点

  • 适合大规模的数据恢复
  • 对数据完整性和一致性要求不高

缺点

  • 在一定间隔时间做一次备份,如果redis意外宕机,会丢掉最后一次快照后的所有修改
  • RDB使用fork()产生子进程进行数据的持久化,如果数据比较大的话可能就会花费点时间,造成Redis停止服务几毫秒。如果数据量很大且CPU性能不是很好的时候,停止服务的时间甚至会到1秒。

二、AOF(Append Only File)

AOF持久化会把被执行的写命令写到AOF文件的末尾,记录数据的变化。默认情况下,Redis是没有开启AOF持久化的,开启后,每执行一条更改Redis数据的命令,都会把该命令追加到AOF文件中,这就相当于是把redis执行过的所有指令记录下来(读操作不记录),有点类似历史记录,恢复数据时将这个文件全部执行一遍。这会降低Redis的性能,但大部分情况下这个影响是能够接受的,另外使用较快的硬盘可以提高AOF的性能。AOF保存的是appendonly.aof文件

在配置文件中redis.conf开启AOF和关于AOF的配置操作:

# appendonly参数开启AOF持久化,默认是no
appendonly no

# AOF持久化的文件名,默认是appendonly.aof
appendfilename "appendonly.aof"

# AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的
dir ./

# 同步策略
# appendfsync always 表示每次写入都执行fsync,以保证数据同步到磁盘。
appendfsync everysec #表示每秒执行一次fsync,可能会导致丢失这1s数据。
# appendfsync no 表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快。


# aof重写期间是否同步,默认no即可,保证数据安全
no-appendfsync-on-rewrite no

# 重写触发配置,设置重写的基准值
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# 加载aof出错如何处理
aof-load-truncated yes

# RDB和AOF的混合持久化
aof-use-rdb-preamble yes

# 文件重写策略
aof-rewrite-incremental-fsync yes

1、AOF的实现

AOF需要记录Redis的每个写命令,步骤为:命令追加(append)文件写入(write)文件同步(sync)

命令追加(append)

开启AOF持久化功能后,服务器每执行一个写命令,都会把该命令以协议格式先追加到aof_buf缓存区的末尾,而不是直接写入文件,避免每次有命令都直接写入硬盘,减少硬盘IO次数

文件写入(write)和文件同步(sync)

对于何时把aof_buf缓冲区的内容写入保存在AOF文件中,Redis提供了多种策略

  • appendfsync always:将aof_buf缓冲区的所有内容写入并同步到AOF文件,每个写命令都同步写入磁盘
  • appendfsync everysec:将aof_buf缓存区的内容写入AOF文件,每秒同步一次,该操作由一个线程专门负责
  • appendfsync no:将aof_buf缓存区的内容写入AOF文件,什么时候同步由操作系统来决定

appendfsync选项的默认配置为everysec,即每秒执行一次同步

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

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

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

从上面的介绍我们知道,我们写入的数据,操作系统并不一定会马上同步到磁盘,所以Redis才提供了appendfsync的选项配置。

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

2、AOF重写

随着时间的推移,Redis执行的写命令会越来越多,AOF文件也会越来越大,过大的AOF文件可能会对Redis服务器造成影响,如果使用AOF文件来进行数据还原所需时间也会越长。因此为避免出现此种情况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis 就会启动AOF 文件的内容压缩,只保留可以恢复数据的最小指令集。

文件重写可以自动触发也可以手动触发执行bgrewriteaof 命令

自动触发会根据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

手动触发执行bgrewriteaof,该命令的执行跟bgsave触发快照时类似的,都是先fork一个子进程做具体的工作

执行bgrewriteaof命令,重写的流程:

image

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

3、AOF文件损坏

当AOF被损坏时候,启动redis,客户端连接时会出现Connection refused

这时可以使用redis-check-aof --fix 进行修复

image

如果出现Successfully truncated AOF,就修复成功,重启可以恢复数据。连接客户端后可以get到数据

4、Redis4.0开始支持RDB和AOF的混合持久化

可以通过配置项 aof-use-rdb-preamble 开启,默认就是yes开启的

image

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

5、优缺点

优点

  • 数据更完整,安全性更高,秒级数据丢失(取决fsync策略,如果是everysec,最多丢失1秒的数据)
  • AOF文件是一个只进行追加的日志文件,且写入操作是以Redis协议的格式保存的,内容是可读的,适合误删紧急恢复

缺点

  • 对于相同的数据集,AOF文件的体积要大于RDB文件,数据恢复也慢于rdb
  • 根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB。

参考:

1、https://juejin.im/post/684490... Redis持久化机制:RDB和AOF TurboSnail


谢谢您看完这篇技术文章

如果能对您有所帮助

那将是一件很美好的事情

保持好奇心的终身学习也是极棒的事

愿世界简单又多彩

转载请注明出处

​ ——纸飞机


纸飞机78
18 声望4 粉丝