持久化是指数据写到物理硬盘里,即便程序崩溃、或者电脑重启,依然能够恢复。Redis提供了两种持久化机制:RDB和AOF。
RDB(Redis Database): RDB文件相当于内存快照,保存了某个时间点数据库信息。使用RDB文件恢复很简单,将文件读取到内存里即可。
AOF(Append Only File):以追加写的方式记录对数据库的修改命令。使用它恢复的时候,会对文件里的命令进行重放,这样也能够还原成数据库原来的样子。
两种方式各有优缺点:
优点 | 缺点 | |
RDB | 恢复快,文件小 | 最坏情况下两次快照之间间隔数据会丢失。 |
AOF | 根据刷盘策略不同,异常情况下数据损失小。 | 恢复慢、AOF文件随着程序运行会逐渐增大。 |
下面详细介绍两种方式的实现细节:
RDB:
RDB既可以手动生成,也可以通过配置让服务器自动生成。Redis提供了save和bgsave两个命令用于生成RDB文件,这两个命令区别在于save会阻塞服务器进程,bgsave不会。bgsave会创建一个子进程来生成,而父进程可以继续执行客户端请求。
另外也可以通过配置文件或者启动参数,使得服务器在满足条件情况下自动生成RDB,默认的配置是:
save 900 1 // 900秒内有一次更改
save 300 10 // 300秒内有十次更改
save 60 10000 // 60秒内有1万次更改
AOF:
AOF通过记日志的方式来实现持久化,这里的日志指的是对数据库有修改的命令。AOF记录日志的流程如下:
1. 处理请求
2. 写文件缓存 write操作
3. 刷新文件缓存到磁盘。fsync操作
相对于内存读写,刷盘需要操作硬件,是一个速度很慢的操作,如果每个redis修改命令都要刷盘,那将极大降低redis的性能。为此,Redis提供了三种不同的刷盘策略:
Always | 每次请求后都要刷盘,性能最差,安全性最高。最多损失一次事件处理数据。 |
Every Sec | 每秒刷盘,兼顾性能和安全,默认选项。最多损失一秒数据。 |
No | 不刷盘,实际刷盘时间取决于操作系统。linux默认会30秒刷一次 |
随着程序的运行,AOF文件会逐渐变大,过大的文件会带来一系列问题:系统文件大小限制、恢复慢、内容冗余。
假设执行100条命令新建100个key,然后执行100条Del命令删除key,此时AOF文件会记录200条命令,然而在恢复的时候,这200条命令完全冗余,不会对数据库产生任何影响。为了解决AOF文件过大的问题,Redis提供了AOF Rewrite机制。
AOF Rewrite既可以通过手动执行bgrewriteaof命令触发,也可以通过配置使得服务器自动执行。执行流程如下:
1.服务器创建子进程
2.子进程根据当前内存数据库构造重建命令,比如一个含有10个key的集合,使用一条
sadd v1,v2,v3,v4......v10。当然,如果一个命令参数过多的话,Redis会分成多条命令执行。这些命令会写入到一个临时文件中。当构造完成好之后,子进程发送一个信号给父进程,父进程收到后会原子替换临时文件和旧的aof文件来完成aof重写,后续的日志会直接写入到新的aof文件。对于子进程在重建aof文件过程中,父进程会继续处理客户端请求,此时,除了追加到旧的aof buffer文件外,还会写到 aof rewrite buffer,当子进程重建完成后,会将aof rewrite buffer内容追加到新的aof文件中,因而不会造成数据丢失。整个过程中,父进程只会在处理信号函数回调的时候阻塞下,最耗时的AOF文件重构过程由子进程完成,不会影响父进程继续处理请求。
综上所述,可以发现,无论是RDB持久化还是AOF持久化,Redis均不能保证数据不丢失。所以,对于某些数据敏感的业务,是否使用redis需要做好评估。这一点,MySQL的WAL(write ahead log)写前日志机制就不错,保证数据不丢。
实际应用中,一般会同时开启RDB持久化和AOF持久化,Redis Server启动的时候会优先使用AOF文件初始化,RDB文件主要用于同步备机等等,另外Redis 4.0版本提供了一个参数,使得程序初始化的时候同时使用rdb和aof初始化,aof-use-rdb-preamble。
参考文档:
1. Redis persistence demystified