Redis持久化
Redis持久化
概述
Redis
的高性能是由于其将所有数据都存储在了内存中,为了使Redis
在重启之后仍能保存数据不丢失,需要将数据从内存中同步到硬盘中,这一过程就是持久化。
Redis
支持两种方式的持久化,一种是RDB
方式,一种是AOF
方式。可以单独使用其中一种或两种结合使用。
-
RDB
持久化(默认支持,无需配置):该机制是指在指定的时间间隔内将内存中的数据集快照写入磁盘。 -
AOF
持久化:该机制将以日志的形式记录服务器所处理的每一个写操作,在Redis
服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的。 - 无持久化:我们可以通过配置的方式禁用
Redis
服务器的持久化功能,这样我们就可以将Redis
视为一个功能加强版的memcached
了。 -
redis
可以同时使用RDB
和AOF
。 - 由于
Redis
的数据都存放在内存中,如果没有配置持久化,redis
重启后数据就全丢失了,于是需要开启redis
的持久化功能,将数据保存到磁盘上,当redis
重启后,可以从磁盘中恢复数据。redis
提供两种方式进行持久化,一种是RDB
持久化(原理是将Redis
在内存中的数据库记录定时dump
到磁盘上的RDB
持久化),另外一种是AOF
持久化(原理是将Redis
的操作日志以追加的方式写入文件)。
RDB
RDB
持久化是把当前进程数据生成快照保存到硬盘的过程,触发RDB
持久化过程分为手动触发和自动触发。
-
保存:
RDB
文件保存在dir
配置指定的目录下,文件名通过dbfilename
配置指定。可以通过执行config set dir {newDir}
和config set dbfilename {newFileName}
运行期动态执行,当下次运行时RDB
文件会保存到新目录。 -
压缩:
Redis
默认采用LZF
算法对生成的RDB
文件做压缩处理,压缩后的文件远远小于内存大小,默认开启,可以通过参数config set rdbcompression {yes | no}
动态修改。 -
校验: 如果
Redis
加载损坏的RDB
文件时拒绝启动,并打印如下日志:Short read or OOM loading DB. Unrecoverable error, aborting now.
这时可以使用Redis
提供的redis-check-dump
工具检测RDB
文件并获取对应的错误报告。
触发机制
手动触发分别对应
save
和bgsave
命令。
- save命令:阻塞当前
Redis
服务器,直到RDB
过程完成为止,对于内存比较大的实例会造成长时间阻塞,先上环境不建议使用。运行save
命令对应Redis
日志如下:DB saved on disk
。 -
bgsave
命令:Redis
进程执行fork操作创建子进程,RDB
持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段,一段时间很短。运行bgsave
名字对应的Redis
日志如下:
Background saving started by pid 3152
DB saved on disk
RDB: 0MB of memory userd by copy-on-write
Background saving terminated with success
-
bgsave
命令是针对save阻塞问题做的优化。因此Redis
内部所有涉及到RDB
操作都采用bgsave
的方式,而save
命令可以废弃。Redis
内部还存在自动触发RDB
的持久化机制,例如一下场景:
- 使用
save
相关配置,如save m n
表示m秒之内数据集存在n
次修改时,自动触发bgsave
。 - 如果从节点执行全量复制操作,主节点自动执行
bgsave
生成RDB
文件并发送给从节点。 - 执行
debug reload
命令重新加载Redis
时,也会自动触发save操作。 - 默认情况下执行
shutdown
命令时,如果没有开启AOF
持久化功能则自动执行bgsave
。
bgsave
命令执行流程如下:
- 执行
bgsave
命令,Redis
父进程判断当前是否存在正在执行的子进程,例如RDB/AOF
子进程,如果存在bgsave
命令直接返回。 - 父进程执行
fork
操作创建子进程,fork
操作过程中父进程会阻塞,通过info stats
命令查看latest_fork_usec
选项,可以获取最近一个fork
以操作的耗时,单位为微秒。 - 父进程仍
fork
完成后,bgsave
命令返回Background saving started
信息并不再阻塞父进程,可以继续响应其他命令。 - 子进程创建
RDB
文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。执行lastsave
命令可以获取最后一次生成尺RDB
的时间,对应info
统计的rdb_last_save_time
选项。 - 进程发送信号给父进程以示完成,父进程更新统计信息,具体见
info Persistence下的rdb_*
相关选项。
优势
-
RDB
是一个紧凑压缩的二进制文件,代表Redis
在某一个时间点上的数据快照。非常适合用于备份,全量复制等场景。比如每6小时执行bgsave
备份,并把RDB
文件拷贝到远程机器或者文件系统中(如hdfs
),用于灾难恢复。
Redis加载RDB恢复数据远远快于AOF方式。
- 一旦采用该方式,那么你的整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美的。比如,你可能打算每个小时归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据。通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
- 对于灾难恢复而言,RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。
- 性能最大化。对于
Redis
的服务进程而言,在开始持久化时,它唯一需要做的只是fork
出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO
操作了。 - 相比于
AOF
机制,如果数据集很大,RDB
的启动效率会更高。
劣势
-
RDB
方式数据没办法做到实时持久化/秒级持久化。因为bgsave
每次运行都要执行fork
操作创建子进程,属于重量级操作,频繁执行成本过高。 -
RDB
文件使用特定二进制格式保存,Redis
版本演进过程中有多个格式的RDB
版本,存在老版本Redis
服务无法兼容新版RDB
格式的问题。 - 如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么
RDB
将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。 - 由于
RDB
是通过fork
子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。
AOF
-
AOF(append only file)
持久化:以独立日志的方式记录每次写命令,重启时再重新执行AOF
文件中命令达到恢复数据的目的。AOF
的主要作用是解决了数据持久化的实时性,目前已经是Redis
持久化的主流方式。
AOF
执行流程如下:
- 开启
AOF
功能需要设置配置:appendonly yes
,默认不开启。AOF
文件通过appendfilename
配置设置,默认文件名是appendonly.aof
。保存路径同RDB
持久化方式一致。通过dir
配置指定。 -
AOF
的工作流程操作:命令写入(append)、文件同步(sync)、文件重写(rewrite)、重启加载(load),工作流程如上。
- 所有的写入命令会追加到
aof_buf
(缓冲区)中。 -
AOF
缓冲区根据对应的策略向硬盘做同步操作。 - 随着
AOF
文件越来越大,需要定期对AOF
文件进行重写,达到压缩的目的。 - 当
Redis
服务重启时,可以加载AOF
文件进行数据恢复。了解AOF
工作流程。
文件同步
-
Redis
提供了多种AOF
缓冲区同步文件策略,由参数appendsync
控制,不同值的含义不同。 - 下表是
AOF
缓冲区同步文件策略
可配置值 | 说明 |
---|---|
always | 命令写入aof_buf 后调用系统fsync 操作同步到AOF 文件,fsync 完成后线程返回 |
everysec | 命令写入aof_buf 后调用系统write 操作,write 完成后线程返回。fsync 同步文件操作由专门线程每秒调用一次 |
no | 命令写入aof_buf 后调用系统write操作,不对AOF 文件做fsync 同步,同步硬盘操作由系统负责,通常同步周期最常为30秒 |
-
always
:每次有数据修改发生时都会写入AOF
文件; -
everysec
:每秒钟同步一次,该策略为AOF
的缺省策略(最常用); -
no
:从不同步。高效但是数据不会被持久化; - 重写
AOF
:若不满足重写条件时,可以手动重写,命令:bgwriteaof
。
系统调用
writ
和fsync
说明
-
write
操作会触发延迟写(delayed write
)机制,Linux在内核提供页缓冲区用来提高硬盘IO
性能。write
操作在写入系统缓冲区后直接返回。同步硬盘操作依赖于系统调度机制,例如:缓冲区页空间写满或达到特定时间周期。同步文件之前,如果此时系统故障宕机,缓冲区内数据将丢失。 -
fsync
针对单个文件操作(比如AOF
文件),做强制硬盘同步,fsync
将阻塞直到写入硬盘完成后返回,保证了数据持久化。
- 配置为
always
时,每次写入都要同步AOF
文件,在一般的STAT硬盘上,Redis
只能支持大约几百TPS
写入,显然跟Redis
高性能特性背道而驰,不建议配置。 - 配置为
no
,由于操作系统每次同步AOF
文件的周期不可控,而且会极大每次同步硬盘的数据量,虽然提升了性能,但数据安全性无法保证。 -
配置为
everysec
,是建议的同步策略,也是默认配置,做到兼顾性能和数据安全性,理论上只有在系统突然宕机的情况下丢失1s
的数据。(严格来说最多丢失1s
数据是不准确的)。
优势
- 该机制可以带来更高的数据安全性,即数据持久性。
Redis
中提供了3
种同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。至于无同步,无需多言,我想大家都能正确的理解它。 - 由于该机制对日志文件的写入操作采用的是
append
模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis
下一次启动之前,我们可以通过redis-check-aof
工具来帮助我们解决数据一致性的问题。 - 如果日志过大,
Redis
可以自动启用rewrite
机制。即Redis
以append
模式不断的将修改数据写入到老的磁盘文件中,同时Redis
还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite
切换时可以更好的保证数据安全性。 -
AOF
包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。
劣势
- 对于相同数量的数据集而言,
AOF
文件通常要大于RDB
文件。RDB
在恢复大数据集时的速度比AOF
的恢复速度要快。 - 根据同步策略的不同,
AOF
在运行效率上往往会慢于RDB
。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB
一样高效。
AOF重启加载流程
-
AOF
和RDB
文件都可以用于服务器重启时的数据恢复。如图所示,表示Redis
持久化文件加载流程: