持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
引言
Redis是基于内存的非关系型K-V数据库,既然它是基于内存的,如果Redis服务器挂了,数据就会丢失。为了避免数据丢失了,Redis提供了持久化,即把数据保存到磁盘。
Redis 的持久化机制有哪些?说说优缺点
Redis 提供了 RDB 和 AOF 两种持久化方式,RDB 是把内存中的数据集以快照形式写入磁盘,默认是通过 fork 子进程执行,采用二进制压缩存储;AOF 是以文本日志的形式记录 Redis 处理的每一个写入或删除操作。
RDB(Redis DataBase)
RDB持久化,是指在指定的时间间隔内,执行指定次数的写操作,将内存中的数据集以快照形式写入磁盘,它是Redis默认的持久化方式,通过 fork 子进程执行,采用二进制压缩存储。执行完操作后,在指定目录下会生成一个dump.rdb文件,Redis 重启的时候,通过加载dump.rdb文件来恢复数据。RDB触发机制主要有以下几种:
-
手动触发:
- save : 同步,会阻塞当前redis服务器
- bgsave :异步,redis进程执行fork操作创建子进程
-
自动触发:
- save m n : m秒内数据集存在n次修改,自动触发bgsave
RDB 的优点
- 适合大规模的数据恢复场景,如备份,全量复制等
RDB缺点
- 没办法做到实时持久化/秒级持久化。
AOF(append only file)
AOF 持久化,Redis 是先执行命令,然后采用日志的形式来记录每个写入或删除操作,追加到文件中,重启时再重新执行AOF文件中的命令来恢复数据。它主要解决数据持久化的实时性问题。默认是不开启的。
AOF的优点
- 数据的一致性和完整性更高
- 比较适合做灾难性数据误删除的紧急恢复了,比如公司的实习生通过flushall清空了所有的数据,只要这个时候后台重写还没发生,我们马上拷贝一份AOF日志文件,把最后一条flushall命令删了就完事了。
AOF的缺点
- AOF记录的内容越多,文件越大,数据恢复变慢。
- AOF开启后,Redis支持写的QPS会比RDB支持写的要低,因为AOF 日志也是由主进程写回磁盘,当然即使这样性能还是很高,我记得ElasticSearch也是这样的,可以异步刷新缓存区的数据去持久化,
那两者怎么选择?
RDB更适合做冷备,AOF更适合做热备,单独用RDB会丢失很多数据,单独用AOF,数据恢复没有RDB来的快,真出事的时候第一时间用RDB恢复,然后AOF做数据补全!冷备热备一起上,才是互联网时代一个高健壮性系统的王道。这也是Redis官方推荐的一种方法:
Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。简单来说,内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。这样一来,快照不用很频繁地执行,这就避免了频繁 fork 对主线程的影响。而且,AOF日志也只用记录两次快照间的操作,也就是说,不需要记录所有操作了,因此,就不会出现文件过大的情况了,也可以避免重写开销。
RDB快照时数据能修改吗?
虽然bgsave是通过创建子进程来写入RDB快照,不会阻塞主进程,但是写入快照需要一段时间,在这段时间内,如果Redis 还能正常修改数据,那么就会破坏快照的完整性;如果快照执行期间数据不能被修改,Redis 就不能处理对这些数据的写操作,那无疑就会给业务服务造成巨大的影响。
为了快照而暂停写操作,肯定是不能接受的。所以这个时候,Redis 就会借助操作系统提供的写时复制技术(Copy-On-Write, COW),在执行快照的同时,正常处理写操作。
简单来说,bgsave 子进程是由主线程 fork 生成的,可以共享主线程的所有内存数据。bgsave 子进程运行后,开始读取主线程的内存数据,并把它们写入 RDB 文件。
此时,如果主进程对这些数据也都是读操作(例如图中的键值对 A),那么,主进程和bgsave 子进程相互不影响。但是,如果主进程要修改一块数据(例如图中的键值对 C),那么,这块数据就会被复制一份,生成该数据的副本。然后,bgsave 子进程会把这个副本数据写入 RDB 文件,而在这个过程中,主进程仍然可以直接修改原来的数据。
AOF三种写回策略
AOF 日志也是在主线程中执行的,AOF 日志写回磁盘的时机有三种:
- Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘;
- Everysec,每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;
- No,操作系统控制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。
想要获得高性能,就选择 No 策略;如果想要得到高可靠性保证,就选择Always 策略;如果允许数据有一点丢失,又希望性能别受太大影响的话,那么就选择Everysec 策略。
AOF日志文件太大了怎么办?AOF重写
AOF 重写机制就是在重写时,Redis 根据数据库的现状创建一个新的 AOF 文件,也就是说,读取数据库中的所有键值对,然后对每一个键值对用一条命令记录它的写入。
AOF 重写会阻塞吗?
和 AOF 日志由主进程写回不同,重写过程是由子进程 bgrewriteaof 来完成的,这也是为了避免阻塞主线程,导致数据库性能下降。
重写的过程总结为“一个拷贝,两处日志”。
“一个拷贝”就是指,每次执行重写时,主线程 fork 出后台的 bgrewriteaof 子进程。此时,子进程拷贝了父进程的页表,即虚实映射关系,也能共享访问父进程的内存数据这里面就包含了数据库的最新数据。然后,bgrewriteaof 子进程就可以在不影响主线程的情况下,重写日志。
“两处日志”又是什么呢?
因为主线程未阻塞,仍然可以处理新来的操作。此时,如果有写操作,第一处日志就是指正在使用的 AOF 日志,Redis 会把这个操作写到它的缓冲区。这样一来,即使宕机了,这个 AOF 日志的操作仍然是齐全的,可以用于恢复。
而第二处日志,就是指新的 AOF 重写日志。新来的写操作也会被写到重写日志的缓冲区。这样,重写日志也不会丢失最新的操作。等到所有操作记录重写完成后,重写日志记录的这些最新操作也会写入新的 AOF 文件,以保证数据库最新状态的记录。此时,我们就可以用新的 AOF 文件替代旧文件了。