文章目录
- 持久化
- 1、RDB
- 1)触发机制
- 2)bgsave命令的运行流程
- 3)RDB文件的处理
- 4)RDB的优缺点
- 2、AOF
- 1)开启AOF
- 2)AOF工作流程
- 3)AOF同步策略
- 4)重写机制
- 5)重写机制的运行流程
持久化
redis虽然主要进行内存存储,但是也提供了硬盘存储,近似实现了“既要有要”。
Redis实现持久化使用了两种方法:
- RDB(Redis Database Backup,类似于定期存储)
- AOF(Append-Only File,类似于实时存储)
1、RDB
RDB持久化是把当前进程中的全量数据生成一个快照,转成rdb二进制文件并压缩,保存到硬盘的过程(服务器默认开启RDB),RDB在redis中可以手动触发,也可以自动触发。
快照:
快照类似于警察快速在案发现场用相机快速进行取证。即把当时的内存数据,快速记录下来,然后把这些内存数据统统保存到硬盘中,等一下会详细讲述这个过程。
1)触发机制
手动触发:
- save命令:阻塞当前redis服务器知道RDB完成,如果内存过大,RDB操作一次性开销是非常大的,所以这个命令一般不要用。
bgsave
命令:Redis执行fork
操作,创建一个子进程,RDB操作全由子进程完成,阻塞只会发生在fork阶段,时间非常短。
1)fork定义:
- 是Linux内核提供的一个系统调用,用于从当前进程(成为父进程)创建一个和父进程几乎一样的子进程。
- 子进程是父进程的一个副本,继承父进程的内存、代码、打开的文件描述符,但是拥有独立的PID以及独立的内存空间
- 上述过程看上去非常“重量”,实际不然,因为Linux使用了 写时拷贝(Copy-on-Write) 这样的机制去优化。
2)Copy-on-Write:
fork创建子进程的过程不会中不会真的把父进程的所有数据都拷贝到自己的内存空间中,而是只会复制部分基本的元数据(这些数据很少因此较为轻量)。父子进程共享一个内存页面(但是内存空间是隔离的)只有父进程内存数据发生修改,子进程才会把之前父进程的数据写入到自己的内存空间。
自动触发:
-
可以通过redis默认路径:
/etc/redis/redis.conf
修改save配置,指定何种情况redis自动触发RDB。
格式是save m n m是秒 n是数据库修改次数 。如save 60 1
表示1分钟修改过一次或者多次,执行RDB。save ""
表示不进行自动配置。
另外,save配置可以设置多个,满足任意一个配置就会触发RDB。 -
在Redis集群中主节点要全量复制数据给从节点,其中一个过程也会触发RDB,把生成的RDB文件发送给从节点。
-
执行shutdown 命令关闭 Redis 时,执⾏ RDB 持久化。
2)bgsave命令的运行流程
- bgsave发送给父进程,如果父进程有其他子进程正在运行,例如RDB/AOF子进程,那么它会直接返回,不执行。反之,往下执行。
- 父进程执行fork调用,常见一个子进程,在此期间,父进程进入阻塞状态。
- 子进程创建完成,可以继续响应其他命令。
- 子进程把内存中的数据通过特定算法转成二进制rdb文件,放到硬盘中。
- rdb文件生成完成后,通知父进程任务完成,子进程自动退出。
3)RDB文件的处理
- 保存:RDB 文件保存用 dir 配置指定的目录(默认
/var/lib/redis/
)下,文件名通过 dbfilename 配置(默认dump.rdb
)指定。可以通过执行 config set dir {newDir} 和 config set dbfilename {newFileName} 运行期间动态执行备份,并把 RDB 文件复制到新目录。 - 压缩:Redis 默认采用 LZF 算法对生成的 RDB 文件做压缩处理,压缩后的文件远远小于内存大小,默认开启,可以通过参数 config set rdbcompression {yes|no} 动态修改。
ℹ️ 虽然压缩 RDB 会消耗 CPU,但可以大幅降低文件的体积,为便使用到硬盘或通过网络发送到从节点,因此建议开启。
- 校验:如果 Redis 启动时加载损坏的 RDB 文件拒绝启动,支持可以使用 Redis 提供
redis-check-dump
工具检测 RDB 文件并获取对应的错误报告。
4)RDB的优缺点
- RDB 是一个紧凑压缩的二进制文件,代表 Redis 在某个时间点的数据库快照。非常适用于备份,全量复制和灾难恢复。
- Redis 加载 RDB 数据时间远超 AOF 的方式。
RDB 方式数据没办法做到实时持久化 / 秒级持久化。因为 bgsave 每运行都要执行 fork 创建子进程
。RDB 文件使用特有二进制格式保存,Redis 版本通过过程中有多个RDB 版本,兼容性可能有风险
。
2、AOF
AOF(Append Only File)持久化:以独⽴⽇志的⽅式记录每次写命令,重启时再重新执⾏ AOF⽂件中的命令达到恢复数据的⽬的。AOF 的主要作⽤是解决了数据持久化的实时性,⽬前已经是Redis 持久化的主流⽅式。因为它兼顾了数据时效和性能。
1)开启AOF
AOF默认不开启,开启需要在etc/redis/redis.conf
中appendonly修改为yes:
2)AOF工作流程
- 进程写入命令后会把命令另外先写入到一个缓冲区(内存中的一个滴地方)
- AOF缓冲区根据不同策略把缓冲区命令 同步到AOF文件(硬盘)中
- 当AOF文件长度到达一定程度会进行重写操作,达到压缩AOF文件的目的
- Redis重启时会优先根据AOF文件进行解析重启,因为AOF文件数据一定是最新的:
3)AOF同步策略
刚才提到:AOF缓冲区根据不同策略把缓冲区命令同步到AOF文件。
这里的策略Redis提供了三个:
可配置值 | 说明 |
---|---|
always | 命令写入 aof_buf 后调用 fsync 同步,完成后返回 |
everysec | 命令写入 aof_buf 后只执行 write 操作,不进行 fsync。每秒由同步线程进行 fsync。 |
no | 命令写入 aof_buf 后只执行 write 操作,由 OS 控制 fsync 频率。 |
补充说明:
- write是Linux内核的一个系统调用,只会把数据写入到一个缓冲区(内存)不会写入硬盘。
- fsync 也是Linux内核的一个系统调用,他会把缓冲区数据直接同步到硬盘中,执行期间当前进程会进入阻塞状态,不能处理其他命令
- always配置性能最差,非特别重要数据不建议使用
- everysec是默认的redis配置
- no配置由于是操作系统对fsync进行控制,因此不可控,除非数据不太重要,不然也不建议开启。
在实际开发过程中,我们要根据实际需求,启用不同策略。
4)重写机制
刚才讲到,重写机制会会对AOF文件进行压缩,其原理大概是这样的:
源文件:
set key1 value1
set key2 value2
del key1
压缩后的文件:
set key2 value2
实际上就是把命令集合中冗余的部分删除,只关注数据最终的结果。
5)重写机制的运行流程
- 请求执行AOF重写。
如果当前正在执行AOF重写,直接返回。进程正在进行bgsave操作,等待bgsave运行完成,在进行AOF重写。 - 父进程调用fork,创建一个子进程(期间阻塞)
- 子进程创建完之后,父进程不仅会把接下来接收到的命令集合放到原来的aof_buf,还会放到另一个aof_rewrite_buf中。这两个缓冲区缺一不可。
- 子进程在硬盘中创建一个新的AOF文件,把父进程fork那个时刻的内存数据进行重写,然后存放到新的AOF文件中。
- 完成重写后
a. 父进程fork那个时刻的内存数据进行重写,并且放到新的AOF文件中后,子进程通知父进程完成重写
b. 然后把aof_rewrite_buf中的命令直接append到新的AOF文件中。
c. 最后新的AOF文件替换掉旧的AOF文件。