一、持久化的作用
1. 什么是持久化
持久化(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。
持久化Redis所有数据保持在内存中,对数据的更新将异步地保存到磁盘上。
2. 持久化的实现方式
快照方式持久化
快照方式持久化就是在某时刻把所有数据进行完整备份。
例:Mysql的Dump方式、Redis的RDB方式。
写日志方式持久化
写日志方式持久化就是把用户执行的所有写指令(增删改)备份到文件中,还原数据时只需要把备份的所有指令重新执行一遍即可。
例:Mysql的Binlog、Redis的AOF、Hbase的HLog。
二、RDB
1. 什么是RDB
RDB简介
RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储。
在默认情况下, Redis 将数据库快照保存在名字为 dump.rdb的二进制文件中。
在 Redis 运行时, RDB 程序将当前内存中的数据库快照保存到磁盘文件中, 在 Redis 重启动时, RDB 程序可以通过载入 RDB 文件来还原数据库的状态。
工作方式
当 Redis 需要保存 dump.rdb 文件时, 服务器执行以下操作:
- Redis 调用forks。同时拥有父进程和子进程。
- 子进程将数据集写入到一个临时 RDB 文件中。
- 当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。
这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益。
2. RDB的三种主要触发机制
save命令(同步数据到磁盘上)
save 命令执行一个同步操作,以RDB文件的方式保存所有数据的快照。
127.0.0.1:6379> save OK
由于 save 命令是同步命令,会占用Redis的主进程。若Redis数据非常多时,save命令执行速度会非常慢,阻塞所有客户端的请求。
因此很少在生产环境直接使用SAVE 命令,可以使用BGSAVE 命令代替。如果在BGSAVE命令的保存数据的子进程发生错误的时,用 SAVE命令保存最新的数据是最后的手段。
bgsave命令(异步保存数据到磁盘上)
bgsave 命令执行一个异步操作,以RDB文件的方式保存所有数据的快照。
127.0.0.1:6379> bgsave Background saving started
Redis使用Linux系统的fock()生成一个子进程来将DB数据保存到磁盘,主进程继续提供服务以供客户端调用。
如果操作成功,可以通过客户端命令LASTSAVE来检查操作结果。
save 与 bgsave 对比
自动生成RDB
除了手动执行 save 和 bgsave 命令实现RDB持久化以外,Redis还提供了自动自动生成RDB的方式。
你可以通过配置文件对 Redis 进行设置, 让它在“ N 秒内数据集至少有 M 个改动”这一条件被满足时, 自动进行数据集保存操作。
比如说, 以下设置会让 Redis 在满足“ 60 秒内有至少有 1000 个键被改动”这一条件时, 自动进行数据集保存操作:
save 60 1000
3. RDB相关配置
# RDB自动持久化规则 # 当 900 秒内有至少有 1 个键被改动时,自动进行数据集保存操作 save 900 1 # 当 300 秒内有至少有 10 个键被改动时,自动进行数据集保存操作 save 300 10 # 当 60 秒内有至少有 10000 个键被改动时,自动进行数据集保存操作 save 60 10000 # RDB持久化文件名 dbfilename dump-<port>.rdb # 数据持久化文件存储目录 dir /var/lib/redis # bgsave发生错误时是否停止写入,通常为yes stop-writes-on-bgsave-error yes # rdb文件是否使用压缩格式 rdbcompression yes # 是否对rdb文件进行校验和检验,通常为yes rdbchecksum yes
4. RDB的优点
RDB是一个非常紧凑的文件,它保存了某个时间点得数据集,非常适用于数据集的备份,比如你可以在每个小时报保存一下过去24小时内的数据,同时每天保存过去30天的数据,这样即使出了问题你也可以根据需求恢复到不同版本的数据集。
RDB是一个紧凑的单一文件,很方便传送到另一个远端数据中心或者亚马逊的S3(可能加密),非常适用于灾难恢复。
RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能。
与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些。
5. RDB的缺点
耗时、耗性能。RDB 需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求。如果数据集巨大并且CPU性能不是很好的情况下,这种情况会持续1秒,AOF也需要fork,但是你可以调节重写日志文件的频率来提高数据集的耐久度。
不可控、丢失数据。如果你希望在redis意外停止工作(例如电源中断)的情况下丢失的数据最少的话,那么RDB不适合你。虽然你可以配置不同的save时间点(例如每隔5分钟并且对数据集有100个写的操作),是Redis要完整的保存整个数据集是一个比较繁重的工作,你通常会每隔5分钟或者更久做一次完整的保存,万一在Redis意外宕机,你可能会丢失几分钟的数据。