三、Redis持久化

三、Redis持久化

1. Redis如何实现数据不丢失

Redis的读写操作都在内存中,所以Redis的性能才会高,但是当Redis重启后,内存中的数据就会丢失(服务器如果断电后,内存中的数据同样会丢失)。

那么为了保证内存中的数据不会丢失,Redis实现了数据持久化的机制,这个机制把数据存储到磁盘,这样redis重启就能够从磁盘中恢复原有的数据

Redis共有三种数据持久化的方式

  • AOF日志:每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里
  • RDB快照:将某一时刻的内存数据,以二进制的方式写入磁盘
  • 混合持久化方式:Redis4.0新增的方式,集成了AOF和RDB的优点

2. AOF日志是如何实现的

Redis在执行完一条写操作命令后,就会把该命令以追加的方式写入到一个文件里,然后redis重启的时候,会读取改文件记录的命令,然后逐一执行命令的方式来进行数据恢复

注意,第一步是执行,第二步是写入

image-20221208001315711

我这里以「set name xiaolin」的命令作为例子,redis执行了这条命令后,记录在AOF日志的内容如下图:

image-20221208001425641

「*3」表示当前命令有三个部分,每部分都是以「$+数字」开头,后面紧跟着具体的命令、键或值。然后,这里的「数字」表示这部分中的命令、键或值一共有多少字节。例如,「$3 set」表示这部分有 3 个字节,也就是「set」命令这个字符串的长度。

2.1 为什么先执行命令,再把数据写入日志?

两个好处:

  • 避免额外的检查开销:如果先写操作,再执行,如果当前命令语法有问题,恢复日志可能出错
  • 不会阻塞当前写操作命令的执行:写操作成功后,才会记录

风险:

  • 数据可能丢失:写命令和记录日志两个过程,当还没来得及写入的时候就宕机了,数据丢失
  • 可能阻塞其他操作:AOF日志也在主线程,redis把日志文件写入磁盘的时候,会阻塞后续操作无法执行

2.2 AOF写回策略有几种?

Redis 提供了 3 种写回硬盘的策略,控制的就是上面说的第三步的过程。 在 Redis.conf 配置文件中的 appendfsync 配置项可以有以下 3 种参数可填:

  • Always,这个单词的意思是「总是」,所以它的意思是每次写操作命令执行完后,同步将 AOF 日志数据写回硬盘;
  • Everysec,这个单词的意思是「每秒」,所以它的意思是每次写操作命令执行完后,先将命令写入到 AOF 文件的内核缓冲区,然后每隔一秒将缓冲区里的内容写回到硬盘;
  • No,意味着不由 Redis 控制写回硬盘的时机,转交给操作系统控制写回的时机,也就是每次写操作命令执行完后,先将命令写入到 AOF 文件的内核缓冲区,再由操作系统决定何时将缓冲区内容写回硬盘。

image-20221208002239487

2.3 AOF日志过大,会触发什么机制

AOF日志是一个文件,随着执行操作命令越来越多,文件的大小会越来越大。如果AOF日志太大了,就会带来性能问题,比如重启Redis后,需要度AOF文件内容来恢复数据,如果文件过大,整个恢复过程就会很慢

所以Redis为了避免AOF文件过大,提供了AOF重写机制,当AOF文件大小超过锁着定的阈值后,redis就会启用AOF重写机制,来压缩AOF文件

AOF重写机制是在重写时,读取当前数据库中的所有键值对,然后将每一个键值对用一条命令记录到「新的AOF文件」,等到全部记录完后,就将新的AOF文件替换掉现在的AOF文件

举个例子,在没有使用重写机制之前,假设前后执行了「set name xiaolin」和「set name xiaolincoding」这两个命令的话,就会将这两个命令记录到AOF文件

image-20221208002916189

但是在使用重写机制后,就会读取name最新的value(键值对),然后用一条「set name xiaolingcoding」命令记录到新的AOF文件,之前的第一个命令就没必要记录了,因为他属于「历史」命令,没有作用了。这样一来,一个键值对在重写日志中只用一条命令就行了。

重写工作完成后,就会将新的AOF文件覆盖现在的AOF文件,压缩了

2.4 重写AOF日志的过程是怎样的?

redis的重写AOF过程是由后台子进程bgrewriteaof来完成的,这么做可以达到两个好处:

  • 子进程进行AOF重写期间,主进程继续处理命令请求,避免阻塞
  • 子进程带有主进程的数据副本,使用子进程而不是线程,因为如果是多线程,多线程之间共享内存,修改内存数据就要通过加锁保证安全。

个人感觉大概记住:但是重写过程中,主进程依然可以正常处理命令

3. RDB快照是如何实现的呢?

因为AOF日志记录的是操作命令,不是实际的数据,所以用AOF方法做故障恢复的时候,需要全量把日志都执行一遍,一旦AOF日志非常多,势必会造成Redis的恢复操作缓慢

为了解决这个问题,Redis增加了RDB快照。所谓的快照,就是记录某一个瞬间的东西,比如当我们给风景拍照的时候,那一瞬间的画面和信息就记录到了一张照片

所以,RDB快照就是记录某一个瞬间的内存数据,记录的是实际数据,而AOF文件记录的是命令操作的日志,而不是实际的数据

因此在redis恢复数据的时候,RDB恢复数据的效率会比AOF高一些,因为直接将RDB文件读入内存就可以,不需要像AOF那样还需要额外执行操作命令的步骤才能恢复数据

3.1 RDB做快照时会阻塞线程吗

redis提供了两个命令来生成RDB文件,风别是sabe和bgsave,他们的区别就在于是否在「主线程」里执行:

  • 执行了save命令,就会在主线程生成RDB文件,由于和执行操作命令在同一个线程,所以如果写入RDB文件的时间太长,会阻塞主线程
  • 执行了bgsave命令,会创建一个子进程来生成RDB文件,这样可以避免主线程的阻塞

配置文件可以配置,每隔一段时间自动执行一次bgsave命令,默认会提供以下配置。注意,别看选项名叫save,实际上执行的是bgsave命令,也就是会创建子进程来生成RDB快照文件。只要满足条件中的一个,就会执行bgsave,他们的意思分别是:

1
2
3
save 900 1  # 900秒之内,对数据库进行了至少1次修改
save 300 10 # 300秒之内,对数据库进行了至少10次修改
save 460 10000 # 60秒之内,对数据库进行了至少10000次修改

这里提一点,Redis的快照是全量快照,也就是说每次执行快照,都是把内存中的「所有数据」都记录到磁盘中。所以执行快照是一个比较重的操作,如果频率太频繁,可能会对redis性能产生影响。如果频率太低,服务器故障时,丢失的数据会更多

3.2 RDB在执行快照的时候,数据能修改吗?

可以,在执行bgsave的过程中,redis依然可以继续处理操作命令,也就是数据是能被修改的,关键的技术就在于写时复制技术(Copy-On-Write,COW)

执行bgsave命令的时候,会通过fork()创建子进程,此时子进程和父进程是共享同一片内存数据的,因为创建子进程的时候,会复制父进程的页表,但是页表指向的物理内存还是一个,此时如果主线程执行读操作,则主线程和bgsave子进程互相不影响

image-20221208141150950

如果主进程执行写操作,则被修改的数据会复制一份副本,然后bgsave子进程会把该副本写入RDB文件,在这个过程中,主线程仍然可以直接修改原来的数据

image-20221208141317879

4. 为什么会有混合持久化

RDB优点是数据恢复速度快,但是快照的频率不好把握,频率太低,丢失的数据就比较多,频率太高就会影响性能。

AOF的优点是丢失数据少,但是数据恢复不快

为了集成两者的优点,redis4.0提出了混合使用AOF日志和RDB内存快照的方式,也叫做混合持久化,既保证了redis的重启速度,又降低数据丢失风险

混合持久化工作在AOF日志重写 过程,当开启了混合持久化时,在AOF重写日志时,fork出来的重写子进程会先将与主线程共享的内存数据以RDB方式写入到AOF文件中,然后主线程处理的操作命令会被记录在重写缓冲区里,重写缓冲区里的增量命令会以AOF方式写入到AOF文件。写入完成后通知主进程将新的含有RDB格式和AOF格式的AOF文件,替换掉旧的AOF文件

也就是说,使用了混合持久化,AOF文件的前半部分是RDB格式的全量数据,后半部分是AOF格式的增量数据

image-20221208142419068

这样的好处在于,重启Redis加载数据的时候,由于前半部分是RDB内容,这样加载时候速度会很快

加载完RDB的内容后,才会加载后半部分的AOF内容,这里的内容是Redis后台子进程重写AOF期间,主线程处理的操作命令,可以使得数据更少的丢失

  • 混合持久化的优点:

混合持久化结合了RDB和AOF持久化的优点,开头为RDB的格式,使得Redis可以更快的启动。同时结合AOF的优点,有效降低了大量数据丢失的风险

  • 混合持久化缺点:

AOF文件添加了RDB格式的内容,使得AOF文件可读性变差

兼容性差,如果开启混合持久化,那么此混合持久化的AOF文件,就不能用在redis4.0之前的版本了


三、Redis持久化
http://example.com/2022/12/07/develop/redis/三、Redis持久化/
作者
Curious;
发布于
2022年12月7日
许可协议