redis 持久化
所谓的持久化,就是把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。 redis 开始是将所有数据保持在内存中,对数据的更新将根据策略配置异步地保存在磁盘中。
持久化的方式
快照方式
快照是某时某刻对数据的完整备份。在以下数据持久化时被使用:
- MySQL Dump
- Redis RDB
日志
数据库做任何操作的更新就将它记录在日志中,当某时刻需要将数据恢复的时候,只需要将日志中的操作重新执行一遍,便得到某时某点的完整数据。在以下数据持久化时被使用:
- MySQL Binlog
- Hbase HLog
- Redis AOF
redis持久化方式
RDB
经过RDB之后,redis会将内存中的数据创建一份快照到硬盘中,称为RDB文件(二进制,直接查看是乱码)。当redis重新启动时,会加载硬盘中的RDB文件,加载到内存中完成数据恢复。
RDB 的触发方式 - 主要三种方式
- save(同步–命令)
- bgsave(异步–命令)
- 自动(配置文件中设置)
save(同步)
执行流程如下:
- 在 save 的同时,其他命令会阻塞等待
- 如果存在老的 RDB 文件,会先创建一个临时文件,然后对老文件进行替换
- 时间复杂度,O(n)
bgsave(异步)
执行流程如下:
- 调用 bgsave 后,会调用 linux 的 fork() 函数,创建一个子进程
- 如果存在老的 RDB 文件,会先创建一个临时文件,然后对老文件进行替换
- 时间复杂度,O(n)
- 子进程名称:redis-rdb-bgsave
自动方式
- 内部相当于bgsave
- Redis(6.2.6版本)默认的save配置如下表:
配置 | second | changes |
---|---|---|
save | 3600 | 1 |
save | 300 | 100 |
save | 60 | 10000 |
满足以上任一条件,将创建(bgsave)RDB 文件(二进制)。比如 60秒内,有10000 条数据发生改变,将自动生成 RDB 文件。此方式的优点是生成的二进制文件是紧凑型的,可按需备份,而且通过RDB恢复数据的速度远远快于AOF。缺点是不好控制 RDB 文件的生成,如果写入量很大的话 RDB 生成太过频繁,频繁写入硬盘,对硬盘负担很大;无法实时持久化(bgsave每次都要fork建立子进程,属于重量级操作),且生成的文件是二进制文件,新旧版本可能存在不兼容的情况。
RDB 相关配置
配置项 | 默认值 | 含义 |
---|---|---|
dbfilename | dump.rdb | RDB快照文件名 |
dir | ./ | RDB快照文件生成所在目录 |
stop-writes-on-bgsave-error | yes | bgsave时发生错误是否停止写入 |
rdbcompression | yes | RDB文件是否采用压缩 |
rdbchecksum | yes | 是否对RDB进行校验 |
RDB 最佳配置
- 不配置自动RDB操作
- dbfilename dump-${port}.rdb
- dir /redisDataPath
- stop-writes-on-bgsave-error yes
- rdbcompression yes
- rdbchecksum yes
触发机制
以下几种情况会触发生成快照:
- 客户端执行命令save和bgsave时会生成快照
- 根据配置文件save m n规则进行自动快照
- 主从复制时从节点执行全量复制,master 节点会执行 bgsave并将RDB文件发给从节点
- debug reload命令重新加载redis
- 默认执行shutdown时,如果没有开启AOF,则自动执行bgsave
- 客户端执行shutdown关闭redis时,触发快照
AOF
通过日志方式将redis中的写命令进行日志记录,保存在硬盘文件中。日志记录的实质是将写命令写在硬盘的缓冲区中,再根据相关策略把数据刷新到磁盘中。当redis服务器启动时候,执行硬盘中的日志文件以恢复redis中的数据。如果日志文件很大(数据量大),恢复速度可能比较慢。
AOF 运行原理 - 创建
AOF 运行原理 - 恢复
AOF 的三种刷新策略
策略 | 含义 |
---|---|
always | 执行每条写命令都会将写命令写到磁盘中 |
everysec | 每秒将数据从缓冲区刷到磁盘中,可能会丢失一秒的数据(redis 默认使用该策略) |
no | 写命令何时刷新的磁盘中,由操作系统来决定 |
AOF 重写
注意这里的重写并不是说将 redis 命令重新抽象成新的 redis 命令,再写入 AOF 文件,而是执行 redis 命令后将内存中的数据进行回溯,重写成 AOF 文件。
- 重写的作用:减少磁盘占用、加速AOF恢复速度
例如一千次incr key 可以重写为 set key 1000 - AOF 重写实现方式 - bgrewriteaof
客户端发送出一条bgrewriteaof命令后,redis会fork一个子进程完成AOF重写操作逻辑。
AOP 重写实现方式 - AOF 重写配置
- AOF配置项
配置 | 默认值 | 含义 |
---|---|---|
auto-aof-rewrite-min-size | 64MB | AOF文件重写需要的尺寸,AOF多大时开启重写 |
auto-aof-rewrite-percentage | 100 | AOF文件增长率(当前AOF文件大小超过上一次重写的AOF文件大小的百分之多少才会重写) |
- AOF统计项
统计名 | 含义 |
---|---|
aof_current_size | AOF当前尺寸(单位:字节) |
aof_base_size | AOF上次启动和重写的尺寸(单位:字节) |
- 自动触发时机
- 当前 AOF 文件大小超过最小重写尺寸
- 当前 AOF 文件大小超过上次重写完的 AOF 尺寸的百分之多少(auto-aof-rewrite-percentage)
aof_current_size > auto-aof-rewrite-min-size
(aof_current_size - aof_base_size) / aof_base_size > auto-aof-rewrite-percentage
AOF 相关配置
配置项 | 最佳取值 | 含义 |
---|---|---|
appendonly | yes | 开启AOF |
appendfilename | aof-${port}.aof | AOF文件名 |
appendfsyn | c everysec | AOF策略 |
dir | /redisDataPath | AOF文件所在目录 |
no-appendfsync-no-rewrite | yes | 在执行重写时不进行AOF操作 |
auto-aof-rewrite-percentage | 100 | AOF重写配置(见上文) |
auto-aof-rewrite-min-size | 64MB | AOF重写配置(见上文) |
AOF 重写原理
AOF 重写流程示意图如下:
说明:
- bgrewriteaof触发重写,判断是否当前有bgsave或bgrewriteaof在运行,如果有,则等待该命令结束后再继续执行。
- 主进程fork出子进程执行重写操作,保证主进程不会阻塞。
- 子进程遍历redis内存中数据到临时文件,客户端的写请求继续写入aof_buf 缓冲区和aof_rewrite_buf重写缓冲区保证原AOF文件完整以及新AOF文件生成期间的新的数据修改动作不会丢失。
- 子进程写完新的AOF文件后,向主进程发信号,父进程更新统计信息。 主进程把aof_rewrite_buf中的数据写入到新的AOF文件。
- 使用新的AOF文件覆盖旧的AOF文件,完成AOF重写。
RDB-AOF混合持久化
在redis4.0版本中,相对与之前的版本其中一个比较大的变化是4.0添加了新的混合持久化方式。所谓的混合持久化就是同时结合RDB持久化以及AOF持久化混合写入AOF文件。这样做的好处是可以结合 rdb 和 aof 的优点, 快速加载同时避免丢失过多的数据,缺点是 aof 里面的 rdb 部分就是压缩格式不再是 aof 格式,可读性差。
开启混合持久化
在6.0版本的redis中混合持久化默认关闭的,通过aof-use-rdb-preamble配置参数控制,yes则表示开启,no表示禁用,默认是禁用的,可通过config set修改。
混合持久化过程
混合持久化同样也是通过bgrewriteaof完成的,不同的是当开启混合持久化时,fork出的子进程先将共享的内存副本全量的以RDB方式写入aof文件,然后在将重写缓冲区的增量命令以AOF方式写入到文件,写入完成后通知主进程更新统计信息,并将新的含有RDB格式和AOF格式的AOF文件替换旧的的AOF文件。简单的说:新的AOF文件前半段是RDB格式的全量数据后半段是AOF格式的增量数据。
数据恢复
当我们开启了混合持久化时,启动redis依然优先加载aof文件,aof文件加载可能有两种情况如下:
- aof文件开头是rdb的格式, 先加载 rdb内容再加载剩余的 aof。
- aof文件开头不是rdb的格式,直接以aof格式加载整个文件。
127.0.0.1:6379> DBSIZE
(integer) 7
127.0.0.1:6379> CONFIG sET aof-use-rdb-preamble yes
OK
127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting starte
退出查看,或者另一个终端查看aof文件
也可以通过redis自带的检查命令去检查一下持久化文件是否正确。
[root@k8s-m2 redis]# ./src/redis-check-rdb dump.rdb
[offset 0] Checking RDB file dump.rdb
[offset 26] AUX FIELD redis-ver = '6.2.6'
[offset 40] AUX FIELD redis-bits = '64'
[offset 52] AUX FIELD ctime = '1704348988'
[offset 67] AUX FIELD used-mem = '831144'
[offset 83] AUX FIELD aof-preamble = '0'
[offset 85] Selecting DB ID 0
[offset 107] Checksum OK
[offset 107] \o/ RDB looks OK! \o/
[info] 2 keys read
[info] 0 expires
[info] 0 already expired
[root@k8s-m2 redis]# ./src/redis-check-aof /appendonly.aof
The AOF appears to start with an RDB preamble.
Checking the RDB preamble to start:
[offset 0] Checking RDB file /appendonly.aof
[offset 26] AUX FIELD redis-ver = '6.2.6'
[offset 40] AUX FIELD redis-bits = '64'
[offset 52] AUX FIELD ctime = '1709537259'
[offset 67] AUX FIELD used-mem = '872648'
[offset 83] AUX FIELD aof-preamble = '1'
[offset 85] Selecting DB ID 0
[offset 132] Checksum OK
[offset 132] \o/ RDB looks OK! \o/
[info] 7 keys read
[info] 0 expires
[info] 0 already expired
RDB preamble is OK, proceeding with AOF tail...
AOF analyzed: size=132, ok_up_to=132, ok_up_to_line=1, diff=0
AOF is valid
持久化方式对比
RDB
- 优点:RDB 是一个非常紧凑(compact)的文件,体积小,因此在传输速度上比较快,因此适合灾难恢复。
RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作。
RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。 - 缺点:RDB是一个快照过程,无法完整的保存所以数据,尤其在数据量比较大时候,一旦出现故障丢失的数据将更多。
当redis中数据集比较大时候,RDB由于RDB方式需要对数据进行完成拷贝并生成快照文件,fork的子进程会耗CPU,并且数据越大,RDB快照生成会越耗时。
RDB文件是特定的格式,阅读性差,由于格式固定,可能存在不兼容情况。
AOF
- 优点:数据更完整,秒级数据丢失(取决于设置fsync策略)。
兼容性较高,由于是基于redis通讯协议而形成的命令追加方式,无论何种版本的redis都兼容,再者aof文件是明文的,可阅读性较好。 - 缺点:数据文件体积较大,即使有重写机制,但是在相同的数据集情况下,AOF文件通常比RDB文件大。
相对RDB方式,AOF速度慢于RDB,并且在数据量大时候,恢复速度AOF速度也是慢于RDB。
由于频繁地将命令同步到文件中,AOF持久化对性能的影响相对RDB较大,但是对于我们来说是可以接受的。
混合持久化
- 优点:
混合持久化结合了RDB持久化 和 AOF 持久化的优点, 由于绝大部分都是RDB格式,加载速度快,同时结合AOF,增量的数据以AOF方式保存了,数据更少的丢失。 - 缺点:兼容性差,一旦开启了混合持久化,在4.0之前版本都不识别该aof文件(兼容性问题),同时由于前部分是RDB格式,阅读性较差。
更多关于redis的知识分享,请前往博客主页。编写过程中,难免出现差错,敬请指出