😄作者简介: 小曾同学.com,一个致力于测试开发的博主⛽️,主要职责:测试开发、CI/CD
如果文章知识点有错误的地方,还请大家指正,让我们一起学习,一起进步。
😊 座右铭:不想当开发的测试,不是一个好测试✌️。
如果感觉博主的文章还不错的话,还请点赞、收藏哦!👍
Redis 持久化主要解决数据丢失问题,在Redis中有两种持久化方式:
- RDB 持久化【本篇主要内容】
- AOF 持久化
RDB概述
RDB
全称Redis Database Backup file (Redis 数据备份文件),也叫做Redis 数据快照
。简单来说就是内存中的所有数据都记录到磁盘中。当 Redis 实例故障重启后,从磁盘读取快照文件,恢复数据。(快照文件称为RDB文件,默认是保存在当前运行目录下)
那么 RDB 方式该如何使用?
# 第一种方式【不推荐】
127.0.0.1:6379> save # 由 Redis 主进程来执行RDB,会阻塞所有命令 ,但是当数据量过大时,会导致耗时
# 第二种方式【推荐】
127.0.0.1:6379> bgsave #子进程执行RDB,避免主进程受到影响
另外,Redis 默认有持久化,但是这个持久化只有在停机时才执行,以下案例可以验证默认持久化问题,具体步骤如下:
-
开启
redis server
redis-server /usr/local/etc/redis.conf
-
Redis 客户端建立连接
➜ ~ redis-cli 127.0.0.1:6379> set age 100 OK
-
Ctrl+C关闭 redis server,则会在命令行出现以下内容
在当前目录下,会生成一个dunp.rdb文件,当再次开启服务时,数据会恢复 -
开启服务 redis-server ,然后客户端重新建立连接
➜ ~ redis-cli 127.0.0.1:6379> get age "100"
以上为RDB快照方式,但是有一个问题
问题
:在停机时执行 RDB 快照,但是如果想要每隔一段时间进行数据保存,应该怎么做呢?
解决方式:修改配置文件
,具体如下:
打开 redis.conf 文件,在MAC中配置文件的路径如下:/usr/local/etc/redis.conf 会看到在配置文件中有 snapshotting(快照)相关的配置。
其中,
save 3600 1
save 300 100
save 60 10000
# 含义:3600s内,如果至少有一个key被修改,则执行bgsave,
save "" 表示禁用RDB
#RDB的其他配置也可以在redis.conf文件中设置,例如:
/usr/local/var/db/redis
rdbcompression yes
dbfilename dump.rdb
dir /usr/local/var/db/redis/
如果使用的是 redis-server /usr/local/etc/redis.conf开启服务,则RDB快照文件在
dir /usr/local/var/db/redis/目录下。
如何实现异步持久化?
bgsave 开始时会 fork 主进程得到子进程,子进程共享主进程的内存数据。完成fork后读取内存数据并写入RDB文件。
那么 fork底层到底是怎么实现的呢?
主进程要实现对 redis 数据的读写,要在内存中操作,在linux系统中所有的进程都没有办法直接操作物理内存,而是由操作系统给每个进程分配一个虚拟内存,所以主进程只能操作虚拟内存,而后操作系统会维护一个虚拟内存与物理内存间的映射关系表,这个表就是常说的“页表”。所以主进程操作虚拟内存,虚拟内存基于页表的关系找到物理内存中数据的位置,从未实现了主进程操作物理内存。
执行 fork 的时候会创建一个子进程,fork的过程就是拷贝页表,将页表拷贝给子进程,所以子进程可以根据页表的映射关系,进而操作物理内存。也实现了主进程与子进程的空间共享,这样加快了读写速度。子进程读取数据后再写入新的 RDB 文件,替换旧的RDB文件(这块存在磁盘)。
当时此处有一个问题,主进程在写的同时,子进程在读,可能会出现冲突,或者一些脏数据,为了避免这种问题呢,fork底层采用的是copy-on-write
技术:
- 当主进程执行读操作时,访问共享内存
- 当主进程执行写操作时,会拷贝一份数据,执行写数据。
总结
RDB方式 bgsave 的基本流程?
- fork主进程得到一个子进程,共享内存空间
- 子进程读取内存数据并写入新的RDB文件
- 用新RDB文件替换旧的RDB文件
RDB 会在什么时候执行,save 60 1000代表是什么含义?
- 默认是服务停止时。
- 代表60秒内至少执行1000次修改则触发 RDB
RDB的缺点?
- RDB 执行间隔时间长,两次RDB 之间写入数据有丢失的风险。
- fork子进程,压缩、写出RDB文件都比较耗时。