Redis第二话——持久化存储机制
Redis的强劲性能主要是依靠其数据都存储在内存中,若redis重启或者服务器故障导致redis重启,所有存储在内存中的数据就会丢失。
但是在某些情况下,我们希望Redis在重启后能够保证数据不会丢失。
- 将redis作为nosql数据库使用。
- 将Redis作为高效缓存服务器,缓存被击穿后对后端数据库层面的瞬时压力是特别大的,所有缓存同时失效可能会导致雪崩。
这时我们希望Redis能将数据从内存中以某种形式同步到硬盘上,使得重启后可以根据硬盘中的记录来恢复数据。
Redis支持两种方式的持久化,一种是RDB(Redis Database Backup file)方式、另一种是AOF(append-only-file)方式,两种持久化方式可以单独使用其中一种,也可以将这两种方式结合使用。
- RDB:根据指定的规则“定时”将内存中的数据存储在硬盘上。(即快照)
- AOF:每次执行命令后将命令本身记录下来。
一、RDB
RDB的实现方式为,在指定时间将当前时刻内存中的数据生成一个快照文件(.rdb文件,默认为dump.rdb),并将这个快照文件保存到磁盘上。
这样,即使redis宕机了,下次重启时也可以通过读取这个快照文件来恢复数据。
触发生成rdb快照文件的方式主要有五种:配置文件自动触发、执行save命令、执行bgsave命令、执行shutdown命令、执行flushall命令。
rdb文件默认文件名为dump.rdb,是在配置文件中配置的如果我们想要修改这个名字可以通过rdbfilename配置修改。
1.配置文件自动触发
redis默认的配置文件redis.conf中,有一个自动触发rdb持久化的配置。
这三行配置默认是被注释掉的,使用时多个条件可组合使用,根据自己的需求按规则来配置
这三行命令的意思是:
save 900 1 -> 900秒内有1个key被修改(写操作),则触发RDB
save 300 100 -> 300秒内有100个key被修改(写操作),则触发RDB
save 60 10000 -> 60秒内有10000个key被修改(写操作),则触发RDB
当满足其中任意一个save条件时,都会触发一次bgsave命令进行异步持久化。
2.执行save命令
save命令是一个同步操作,执行该命令后,RDB持久化是在主进程中进行的,这样会阻塞当前redis服务,直到RDB持久化完成后,客户端才能正常连接redis服务。
3.执行bgsave命令
bgsave命令是对save命令的一个优化,是一个异步操作。执行该命令后,redis主进程会通过fork操作创建一个子进程,RDB持久化是由子进程操作,完成后自动结束。
这个过程中,主进程不阻塞,可以继续接收客户端的访问。因此,redis内部所有涉及RDB持久化的操作都是采用的bgsave方式,save命令基本已经废弃。
bgsave的流程可以参考下图:
4.执行shutdowm命令
shutdown触发方式比较简单,只需要在客户端执行shutdown命令即可。
执行shutdown命令后,自动生成了一个dump.rdb文件
5.执行flushall命令
flushall命令是清空redis内存中的数据,并且同时清空dump.rdb文件。
所以这个命令就相当于删库跑路,此处只是说明该命令会触发rdb,实际使用中千万不要执行。
如果之前没有dump.rdb文件,则执行flushall命令后,会生成一个dump.rdb文件。
如果之前已经存在dump.rdb文件,并且里面也存在数据,那么执行flushall命令后,会将原来dump.rdb文件中的内容清空。
二、AOF
AOF是redis提供的另一种数据持久化方式,它会记录客户端对redis服务端的每一次写操作,并将这些写操作以redis协议追加保存到后缀为aof的文件末尾。
在redis服务器重启时,会读取并加载aof文件,达到恢复数据的目的。
aof持久化方式redis是默认不开启的,我们可以通过配置文件开启aof持久化方式。
appendonly的值默认为no,改为yes即可开启aof持久化方式。
AOF的默认文件名为appendonly.aof,也可通过appendfilename配置修改。
两个缓冲区:aof_buf 和 aof_rewrite_buf
1. appendfsync always
客户端对redis服务器的每次写操作都写入AOF日志文件。这种方式是最安全的方式,但每次写操作都进行一次磁盘IO,非常影响redis的性能,所以一般不使用这种方式。
2. appendfsync everysec
每秒刷新一次缓冲区中的数据到AOF文件。这种方式是redis默认使用的策略,是考虑数据完整性和性能的这种方案,理论上,这种方式最多只会丢失1秒内的数据。
3. appendfsync no
redis服务器不负责将数据写入到AOF文件中,而是直接交给操作系统去判断什么时候写入。这种方式是最快的一种策略,但丢失数据的可能性非常大,因此也是不推荐使用的。
AOF文件重写
既然AOF是通过日志追加的方式来存储redis的写指令,那么当我们对同一个key做多次写操作时,就会产生大量针对同一个key操作的日志指令,导致AOF文件会变得非常大,恢复数据的时候会变得非常慢。因此,redis提供了重写机制来解决这个问题。redis通过重写AOF文件,保存的只是恢复数据的最小指令集。
我们可以通过下面命令手动触发重写:bgrewriteaof。
也可以通过配置文件自动触发重写:
auto-aof-rewrite-percentage 100:当文件的大小达到原先文件大小(上次重写后的文件大小,如果没有重写过,那就是redis服务启动时的文件大小)的两倍。
auto-aof-rewrite-min-size 64mb:文件重写的最小文件大小,即当AOF文件低于64mb时,不会触发重写。
只有这两个指标同时满足的时候才会发生重写。
AOF文件的重写流程如下:
(1)bgrewriteaof触发重写,判断是否存在bgsave或者bgrewriteaof正在执行,存在则等待其执行结束再执行;
(2)主进程fork子进程,防止主进程阻塞无法提供服务;
(3)子进程遍历Redis内存快照中数据写入临时AOF文件,同时会将新的写指令写入aof_buf和aof_rewrite_buf两个重写缓冲区,
前者aof_buf是为了定期写回旧的AOF文件,后者aof_rewrite_buf是为了后续刷新到临时AOF文件中,防止快照内存遍历时新的写入操作丢失(防止在aof重写过程中新的写入操作丢失);
(4)子进程结束临时AOF文件写入后,通知主进程;
(5)主进程会将上面的aof_rewirte_buf缓冲区中的数据写入到子进程生成的临时AOF文件中;
(6)主进程使用临时AOF文件替换旧AOF文件,完成整个重写过程。
三、RDB和AOF对比
RDB的优点:
- RDB文件非常紧凑,节省内存空间;
- RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快;
- 适合全量备份、全量复制的场景,经常用于灾难恢复(对数据的完整性和一致性要求相对较低的场合)
RDB的缺点:
- 服务器宕机时,可能会丢失部分数据;
- 每次保存RDB的时候,Redis都要fork出一个子进程,这个过程是阻塞的,如果数据集巨大,那阻塞的时间就会很长。
AOF的优点:
- 数据更加完整,丢失数据的可能性较低;
- AOF日志文件可读,并且可以对AOF文件修复。
AOF的缺点:
- AOF日志记录在长期运行中逐渐庞大,恢复起来非常耗时,需要定期对AOF日志进行瘦身处理;
- 恢复备份速度比较慢。
其他小知识:
官方建议使用RDB持久化或两者共同使用确保数据安全性
目前AOF程序有一些bug
之后会将二者整合成单个持久化模型