原文地址 👉 欢迎访问我的个人博客 👈
Redis 版本:6.0.3
1. Redis 持久化
Redis 持久化可以分为三种:
- RDB 快照(SnapShot)
- AOF(Append-only file)
- 混合持久化(RDB + AOF)
2. RDB
默认情况下,Redis 的内存快照保存在 dump.rdb 的二进制文件中。该文件默认在 redis 安装目录下,当 rdb 文件存在时,redis 启动会先读取rdb文件并恢复数据。
设置 Redis 开启RDB快照有三种方法:
- save:修改 redis.conf 文件,添加 save 命令,格式 save 时间(秒) 执行命令次数。例如
save 60 1000
指在60秒超过1000个改动命令的话自动执行 rdb 快照功能。
# save <seconds> <changes>
#
# Redis will save the DB if both the given number of seconds and the given
# number of write operations against the DB occurred.
# 关闭
save "" # 或者注释掉所有 save 配置即可
-
bgsave:写时复制机制(COW)
- 从redis主线程fork一个子线程,该子线程拥有主线程所有数据
- 子线程将所有数据备份到新的rdb文件(备份过程中,主线程仍可执行命令,不会阻塞)
- 新的rdb文件会覆盖旧的rdb文件
注意:redis 执行命令是单线程的,但不代表redis就是单线程的,像bgsave的子线程和主线程。
在 redis 客户端手动执行 save
和 bgsave
也可以生成rdb备份文件,新生成的 rdb文件会覆盖旧的。
注意:flushall
清除命令会重置rdb文件
Save和Bgsave对比:
save | bgsave | |
---|---|---|
IO | 同步 | 异步 |
是否阻塞主线程 | 是 | 否(fork主线程时会有短暂阻塞) |
复杂度 | O(n) | O(n) |
优点 | 执行时用的是主线程,不会消耗额外内存 | 不阻塞主线程 |
缺点 | 阻塞主线程 | fork主线程时会消耗内存 |
RDB持久化的优缺点:
优点:
- 相比于AOF,数据量较大时,rdb文件更适合作为备份文件,因为其内部数据采用二进制形式存储,恢复数据时会更快更方便
缺点:
- 有几率丢失部分数据,因为SnapShot是固定时间间隔执行的,所以如果在下次Snapshot之前系统出现宕机或者其他问题的话,这段时间尚未备份到rdb的数据便会丢失,最新的rdb文件只会备份到上次Snapshot的数据。
- 当数据量较大时,fork子线程会损耗更多性能
3. AOF
AOF是一种比RDB更灵活持久的备份策略,会将每一条**修改(例如 set lpush等等)**的指令记录到appendonly.aof文件中(RDB是满足条件才会记录)。redis7.0后该文件会被拆分为多个文件。
注意:AOF并不是每次有新命令就会缓存到磁盘文件中,而是先写入系统缓存每隔一段时间在 fsync 到磁盘
Redis 启动时会自动读取aof文件中的命令参数进行命令重写,也就是将每条命令都执行一次。
打开AOF备份策略:修改 redis.conf 文件,将appendonly改为 yes (默认为 no)
appendonly yes
可修备份文件名称:
appendfilename "appendonly.aof"
AOF的备份策略(多久才将数据 fsync 到磁盘文件中):
- appendfsync always: 没有新命令便执行一次 fsync,速度最慢也最安全
- appendfsync everysec:每秒 fsync 一次 (默认)
- appendfsync no:从不 fsync ,将数据交给操作系统来处理。更快,也更不安全的选择。
开启AOF后,每条修改命令都会备份,appendonly.aof 文件里存储的是每条命令的解析,例如执行两条命令
set test1 1
set test2 2
appendonly.aof的内容:
解析:set test1 1
*3:指该命令由三部分组成(1-set 2-test1 3-1)
$3:代表执行的命令长度,例如 set 的长度是3
set:执行的命令
$5:key的长度,如 test1
test1:key
$1:value的长度,如 1
1:value
当AOF文件存储的数据量越来越大,到了一定的程度后会触发AOF Rewriting(重写)。redis 会在后台(fork 一个子线程,不会阻塞主线程)对 aof 文件进行重写,优化那些重复的命令,例如:对某一个key进行重复的增量更新
其在aof文件中的命令如下:可见 incr test1 这个命令重复了四次,如果这个次数是 10000 次 、100000次或者更大呢?那么redis启动读取aof文件并执行命令时就会重复执行相同的命令导致损耗更多的性能。为了解决这个问题,redis引入了重写。
重写可以手动触发也可以自动触发:在控制台输入 bgrewriteaof 可以手动触发重写
bgrewriteaof
自动触发可配置频率:
1 # auto‐aof‐rewrite‐min‐size 64mb //aof文件到设定大小后自动触发重写
2 # auto‐aof‐rewrite‐percentage 100 //aof文件自上一次重写后文件大小增长了100%则再次触发重写
重写功能可以将这些命令进行优化,例如这里的四次 incr 可以直接优化为 set test1 4,这样 redis 无需执行多次的重复命令从而优化性能。
重写后文件大小对比:
重写后的文件内容:已经变成了 set test1 4
注意:开启混合开发后,内容会变成二进制形式
AOF和RDB的对比:
RDB | AOF | |
---|---|---|
优先级 | 低 | 高(RDB和AOF文件同时存在时,redis会优先选择aof) |
体积 | 小 | 大 |
备份回复速度 | 快 | 慢 |
数据安全性 | 容易丢失 | 由备份策略决定 |
4. RDB + AOF 混合持久化
redis4.0 后为了解决RDB容易丢失数据和AOF恢复速度慢的问题引入了混合持久化的概念。开启混合持久化需要将 aof-use-rdb-preamble
改为 yes
开启混合持久化后,RDB无需指定开启,命令默认存储到AOF文件中,每当AOF进行重写时,在重写那一刻会同时进行RDB快照并将RDB快照内容和AOF重写后的内容写入一个新的aof文件中,然后覆盖旧的aof文件。这样redis重启后会先读取aof文件中的RDB内容然后再读取aof自身重写后的内容进行数据恢复从而实现数据恢复效率的提升。
重写后的aof文件内容,以上面的4次incr为例:
其结构为:RDB内容在AOF内容前面,所以恢复数据时先恢复RDB快照内容的数据,再恢复AOF内容的数据。