Redis持久化
一、什么是持久化?
持久化(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML数据文件中等。
持久化是将程序数据在持久状态和瞬时状态间转换的机制。
二、Redis支持的两种持久化方式
Redis的数据都是存储在内存中的,所以Redis持久化也就是要把Redis存储在内存中的数据保存到硬盘。
1. RDB持久化(快照)
2. AOF持久化(只追加操作的文件 Append-only file)
目前我部署的Redis通过RDB持久化(默认)和AOF持久化(配置)备份结合使用。
RDB持久化
RDB持久化是指在客户端输入save、bgsave或者达到配置文件自动保存快照条件时,将Redis 在内存中的数据生成快照保存在名字为 dump.rdb(文件名可修改)的二进制文件中。
Redis可以用一定的频率存储RDB文件,而存储的是Redis中的数据快照,并且为了节省磁盘空间它可以对文件进行压缩;还有就是在保存文件失败后,默认可以让Redis拒绝新的写入请求。
Redis RDB的保存提供了同步阻塞,以及异步非阻塞两类方式:
1. 客户端执行SAVE命令,此方式属于同步阻塞的方式;如若同步阻塞方式保存的快照文件过于庞大有可能会阻塞Redis,使其失去提供服务的能力。
2. 客户端执行BGSAVE命令,此方式属于异步非阻塞的方式,主进程会fork 一个子进程来执行快照的保存;
3. 配置文件SAVE是异步的。
优点
- RDB是一个非常紧凑(有压缩)的文件,它保存了某个时间点的数据,非常适用于数据的备份。
- RDB作为一个非常紧凑(有压缩)的文件,可以很方便传送到另一个远端数据中心 ,非常适用于灾难恢复。
- RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能.
- 与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些。
缺点
- Redis意外宕机 时,会丢失部分数据
- 当Redis数据量比较大时,fork的过程是非常耗时的,fork子进程时是会阻塞的,在这期间Redis 是不能响应客户端的请求的。
注意:在实际应用的时候,要特别注意配置文件快照参数,要不就很有可能服务器频繁满载做dump,会影响性能,增大负载压力),具体可以参考配置文件中的save参数的配置。
# 触发自动保存快照
# save <seconds> <changes>
# save <秒> <修改的次数>
save 900 1
save 300 10
save 60 10000
# 设置在保存快照出错时,是否停止redis命令的写入
stop-writes-on-bgsave-error yes
# 是否在导出.rdb数据库文件的时候采用LZF压缩
rdbcompression yes
# 是否开启CRC64校验 rdbchecksum yes
# 导出数据库的文件名称 dbfilename dump.rdb
# 导出的数据库所在的目录
dir ./
AOF持久化( appendonly yes)
AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态,也就是每当 Redis 执行一个改变数据集的命令时(比如 SET), 这个命令就会被追加到 AOF 文件的末尾。
实现
AOF持久化功能的实现可以分为命令追加(append)、文件写入和文件同步(sync)三个步骤。
原理: 当服务器在执行完一个写命令之后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf内存缓冲区的末尾, 等到缓冲区的空间被填满,或者超过了指定的时限,或者内核需要重用缓冲区存放其它磁盘块数据时,才会真正将缓冲区中的所有数据写入到磁盘里面。
具体可以参考配置文件中的 appendfsync参数的配置。
#appendfsync
# always 每次有新命令时,就将缓冲区数据写入并同步到 AOF 文件
# everysec(默认) 每秒将缓冲区的数据写入并同步到 AOF 文件
# no 将缓冲区数据写入AOF 文件,但是同步操作到交给操作系统来处理
载入与数据还原
读取AOF文件并还原数据库的步骤如下
1. 创建一个不带网络连接的伪客户端
2. 从AOF文件中分析并读取出一条写命令
3. 使用伪客户端执行被读出的写命令
4. 一直执行步骤2、3,知道AOF文件中的所有写命令都被处理完毕为止
这时可能会出现一个问题。服务器可能在程序正在对 AOF 文件进行写入时停机,造成了 AOF 文件出错,那么 Redis 在重启时会拒绝载入这个 AOF 文件,从而确保数据的一致性不会被破坏 当发生这种情况时, 可以用以下方法来修复出错的 AOF 文件:
* 为现有的 AOF 文件创建一个备份。
* 使用 Redis 附带的 redis-check-aof 程序,对原来的 AOF 文件进行修复: redis-check-aof –fix
* (可选)使用 diff -u 对比修复后的 AOF 文件和原始 AOF 文件的备份,查看两个文件之间的不同之处。
* 重启 Redis 服务器,等待服务器载入修复后的 AOF 文件,并进行数据恢复。
另外redis.conf配置文件中还提供了一个参数来控制是否忽略最后一条可能存在问题的指令,如下
aof-load-truncated yes
注意: 在重启服务器之前,需要在Redis-cli工具上输入shutdown save命令,意思是强制让Redis数据库执行保存操作并关闭Redis服务,这样做能保证在执行Redis关闭时不丢失任何数据。
重写
AOF重写是保存的是当前数据库的键值对的状态。它根据值所对应的类型,执行对应的命令操作。 因为在进行AOF命令重写时会进行大量的写入操作,这时如果在服务器进程中来进行重写操作,会阻塞服务器进程,导致其无法处理客户端的请求,为了避免这种情况的发生,AOF重写是在子进程中来完成的。子进程会拷贝服务器进程的数据副本,这样做的好处是保证不再使用锁的情况下保证数据的安全性。
同样,使用子进程带来的一个问题是当子进程进行AOF重写时,服务器进程在这段期间会接收客户端的命令请求,这导致重写后的AOF文件与服务器的状态不一致的情况。为了解决这个情况。redis引入了重写缓冲区的概念,这个重写缓冲区在redis创建AOF子进程重写后使用。重写期间,命令会被写入到缓冲区与重写缓冲区。当子进程完成了AOF文件的重写,会像父进程发送一个重写完成的信号,父进程在接收到信号后,会调用信号处理函数,执行以下操作:
1.重写缓冲区的内容同步到新的AOF文件中。
2.重命名新的AOF文件,覆盖原有的AOF文件。
此时,信号处理函数再父进程执行,会短暂阻塞服务器进程。
具体重写步骤:
1. 创建子进程进行AOF重写
2. 将客户端的写命令追加到AOF重写缓冲区
3. 子进程完成AOF重写工作后,会向父进程发送一个信号
4. 父进程接收到信号后,将AOF重写缓冲区的所有内容写入到新AOF文件中
5. 对新的AOF文件进行改名,覆盖现有的AOF文件
注: AOF重写不需要对现有的AOF文件进行任何读取、分析和写入操作。
重写后的文件包含重写前文件最小的命令集合,整个过程是安全的。
# 自动重写是Redis会记录上次重写的大小,若当前文件的大小超过原来文件的一定比例,将进行自动重写;以示例说明:基础重写大小是64m,若当前aof文件大小是64m的2倍,将自动进行aof的重写。
# 自动重写比例设置
auto-aof-rewrite-percentage 100
# 自动重写最小大小
auto-aof-rewrite-min-size 64mb
Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。
参考整理链接有:https://www.cnblogs.com/fixzd/p/9393990.html