深入Redis:细谈持久化

Redis的数据是保存在内存中的,内存里面的数据是不持久的,要想做到持久化,必须要把在内存中的数据储存到硬盘上。

Redis速度非常快,数据只有在内存中才有这样的速度,但是为了持久,数据还是要想办法保存到硬盘上去。于是,Redis决定,内存中也存数据,硬盘上也存数据,这样的两份数据理论上是完全一样的。

当需要插入一个新的数据的时候,就把这个数据同时写入到内存和硬盘,当查询某个数据的时候直接从内存里面读取,硬盘里面的数据只是在redis重启的时候,用来恢复内存里面的数据的。

具体来说,Redis有两种持久化的策略:RDB和AOF。

目录

RDB

手动触发

bgsave执行流程

dump.rdb

自动触发

AOF

同步频率

重写机制

重写流程

混合持久化


RDB

RDB,Redis DataBase ,也就是定期备份。

RDB定期的把我们Redis内存中的所有数据,都写入到硬盘中,生成一个快照 。后续Redis一旦重启,就可以根据快照来把数据重新恢复到内存中。

"定期",具体来说,有两种方式:手动触发和自动触发。

手动触发

通过redis客户端,执行特定的命令,来触发快照的生成。

这个特定的命令就是 save 或者 bgsave(backgroud)。

执行save的时候,redis会全力以赴的进行"快照生成"操作,此时会阻塞redis的其他客户端的命令。

但是并不推荐这样的方式,因为会占用大量的资源,会导致类似于 keys * 的后果。

所以我们主要讲解的是bgsave。

**bgsave处理的时候,是不会影响到Redis服务器处理其他客户端的请求和命令。**是如何做到的呢?Redis不是单线程的吗?此处Redis使用的就是"多线程"的方式来完成的并发编程。

bgsave执行流程

按照 1) 2) 3) 4) 5)的顺序来看,bgsave在后台异步地保存当前数据库的数据到磁盘。这个过程是通过创建一个子进程(fork)来完成的,这样可以避免在数据保存过程中阻塞主进程,从而影响Redis的性能。等到子进程完成生成RDB文件以后,在通过一个信号通知父进程。

dump.rdb

redis生成的rdb文件,是存放在redis的工作目录中的,可以在redis配置文件中设置。

redis.conf文件中,有一个名为dir的配置项,它指定了RDB文件和AOF文件的存储目录。

复制代码
dir /var/lib/redis

后续redis服务器重新启动,就会尝试加载这个rdb文件。如果这个文件的格式或者某方面有错误,也可能导致数据加载失败。这里具体redis会怎么样,取决于rdb文件坏的地方在哪里,如果坏的地方正好是在文件末尾,就有可能还能正常启动,但是如果中间位置坏了,可能直接启动失败了。

当生成rdb镜像的时候,此时就会要把生成的快照数据,保存到一个临时文件中,当这个快照生成完毕之后,会先删除之前的rdb文件,再把新生成的rdb文件的名字改成刚才的dump.rdb。

自动触发

在Redis配置文件中,可以自己设置Redis每隔多久/修改多少次 就可以触发RDB。

  • save 900 1:如果在900秒(15分钟)内至少有1个键被修改,则保存数据库。
  • save 300 10:如果在300秒(5分钟)内至少有10个键被修改,则保存数据库。
  • save 60 10000:如果在60秒内至少有10000个键被修改,则保存数据库。

假设我们随便插入几个键值对,没有运行手动触发的命令,也达不到自动触发的条件。但是这一些数值都是可以修改的,但是需要注意的是:生成一次RDB快照,成本还是比较高的,不能让这个操作执行的太频繁。

正因为rdb生成的不能太频繁,这就导致快照里面的数据和当前实时的数据情况可能有一些偏差。

  1. 12:00:00 生成了rdb
  2. 12:00:01 redis收到了大量的key变化请求
  3. 12:01:00 生成下一个快照文件

如果在第二步的过程中,redis服务器挂了,或者被异常重启(如kill - 9或者服务器掉电),就会导致12:00:00之后的数据都丢了。解决这个的办法就是AOF,我们之后再说。

如果使用service redis-server restart (shutdown命令),redis服务器也会触发生成快照这一操作。

RDB最大的问题,就是不能实时的持久化保存数据,在两次生成快照之间,实时数据可能会随着服务器重启而丢失。

AOF

AOF,append only file,会把用户的每个操作都记录到文件中,当redis重新启动的时候,就会读取这个aof文件中的内容,用来恢复数据。

AOF一般是关闭状态,通过修改配置文件可以打开。

那redis是一个单线程的服务器,在操作内存的同时,又要实时操作aof,同时写硬盘和内存,速度怎么保证?

实际上,AOF机制并不是直接让工作线程把数据写入硬盘,而是先写数据到内存中的缓冲区,等到有一定量之后再统一写入硬盘。

但是这不就是和RDB一样的问题了吗,如果数据在内存缓冲区里面,还没有写入到硬盘里面就主机掉电等出现异常,那岂不是还是会有部分数据丢失?

同步频率

其实这就是程序员需要做的取舍,redis给出了一些选项,刷新频率越高,性能影响就越大,同时数据的可靠性就越高;刷新频率越低,性能影响就越小,数据的可靠性就越低~

在配置文件中,有一个appendfsync选项可以自行设置。

重写机制

AOF文件持续增长,体积会越来越大,而且会影响到下一次 redis的启动时间。有没有什么办法能够减少AOF的体积呢?在AOF文件中,有一些内容是冗余的,比如:

对于AOF文件来说,我们可以忽略一些操作的过程,只关注操作的结果,这样就能够节省很多的资源占用。这就是Redis的重写机制,能够针对AOF文件进行整理操作,这个整理就能够剔除其中的冗余操作,并且合并一些操作,达到给AOF文件瘦身的效果。

重写流程

对于AOF的重写来说,仍然会创建子进程fork。父进程仍然负责接收请求,子进程负责对AOF文件进行重写。重写的时候,不关心AOF文件中原来都有一些什么,只关心内存中最终的数据状态。子进程只需要把内存中当前的数据获取出来,以AOF的格式写入到一个新的AOF文件中。

因为内存中的数据的状态,就已经相当于把AOF文件整理后的模样了。

  1. 在fork后,子进程写新的AOF文件,父进程仍然在不停的接受客户端的新请求,父进程会把这些请求产生的AOF文件先写到缓冲区里面,再刷新到原来的AOF文件。
  2. 在创建子进程的一瞬间,子进程就继承了当前父进程的内存状态,因此子进程的内存数据是父进程fork之前的状态,fork之后,新来的请求子进程是不知道的,它在自己干自己的事。
  3. 父进程又准备了一个aof_rewrite_buf缓冲区,专门放fork之后收到的数据。等待子进程写完新的AOF文件后,再把缓冲区里面的文件写入到新AOF文件中,就可以用新的AOF文件代替旧的AOF文件了。
  4. 父进程fork完之后,仍然在写旧的AOF文件,并且随着时间的推移新的AOF文件也会完成,那父进程还有必要在fork之后写旧的AOF文件吗?考虑极端情况,fork后子进程重写一半了,但是服务器挂了,子进程的数据就会丢失,新的AOF文件内容还不完整。如果父进程不写旧的AOF文件,重启就无法保证数据的完整性了。

如果在执行bgrewriteaof的时候,此时redis已经在进行AOF重写了,就不会再次执行AOF重写,会直接返回。

如果在执行bgrewriteaof的时候,发现当前redis在生成rdb文件的快照,此时AOF就会等待,等待RDB快照生成完毕再进行AOF重写。

其实AOF这样做的好处就是:RDB对于fork之后的数据就置之不理,而AOF则采用了aof_rewrite_buf来处理。这也就是RDB和AOF的设计理念不同,前者强调定期备份,而后者则是强调实时备份。

混合持久化

AOF本来是按照文本的方式来写入文件的,但是文本的方式写文件,后续加载的成本是比较高的,redis就引入了"混合持久化"的方式,结合了RDB和AOF的特点。

通过这个配置可以打开混合持久化,默认是打开的。

按照AOF的方式,每一个请求、操作都记录到文件里面,在触发了AOF重写操作后,就会把当前的内存按照rdb的二进制格式写入到新的AOF文件中,后续再进行的操作仍然是按照AOF文本的方式追加到文件后面。

当Redis上同时存在AOF文件和RDB快照的时候,以AOF为主,RDB就被忽略了~

至此,Redis持久化就告一段落了~之后还会继续进行Redis的学习~

相关推荐
秃头摸鱼侠44 分钟前
MySQL查询语句(续)
数据库·mysql
MuYiLuck1 小时前
【redis实战篇】第八天
数据库·redis·缓存
睡觉待开机1 小时前
6. MySQL基本查询
数据库·mysql
�FENG1 小时前
Redis 安装配置和性能优化
redis·持久化
大熊猫侯佩2 小时前
由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(三)
数据库·swiftui·swift
大熊猫侯佩2 小时前
由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(二)
数据库·swiftui·swift
大熊猫侯佩2 小时前
用异步序列优雅的监听 SwiftData 2.0 中历史追踪记录(History Trace)的变化
数据库·swiftui·swift
大熊猫侯佩2 小时前
由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(一)
数据库·swiftui·swift
Ares-Wang2 小时前
负载均衡LB》》HAproxy
运维·数据库·负载均衡
AI.NET 极客圈2 小时前
.NET 原生驾驭 AI 新基建实战系列(四):Qdrant ── 实时高效的向量搜索利器
数据库·人工智能·.net