redis 持久化机制
作者:互联网
redis 持久化的意义
redis 持久化的意义,在于故障恢复。
比如说,你部署了一个 redis,作为 cache 缓存,当然也可以保存一些比较重要的数据。如果没有持久化的话,redis遇到灾难性故障的时候,就会丢失所有的数据,如果通过持久化将数据搞一份在磁盘上去,然后定期去同步和备份到一些云存储服务上去,那么就可以保证数据不丢失全部,还是可以恢复一部分数据回来的
RDB 和 AOF 两种持久化机制的介绍
- RDB持久化机制,对 redis 中的数据执行周期性的持久化
- AOF机制,对每条写入命令作为日志,以 append-only 的模式写入一个日志文件中,在 redis 重启的时候,可以通过回放 AOF 日志中写入指令来重新构建整个数据集
- 通过 RDB 或 AOF,都可以将 redis 内存中的数据持久化到磁盘上面来,然后可以将这些数据备份到别的地方去,比如说云服务(阿里云)。如果 redis 挂了,服务器上的内存和磁盘上的数据都丢失了,可以从云服务上拷贝回来之前的数据,放到指定的目录中去,然后重启 redis,redis 就会自动根据持久化数据文件中的数据,去恢复内存中的数据,继续对外提供服务
- redis支持同时使用 RDB 和 AOF 两种持久化机制,那么在 redis 重启的时候,会使用 AOF 来重新构建数据,因为 AOF 中的数据更加完整
- 如果我们想要 redis 仅仅作为春内存的缓存来使用,那么可以禁止 RDB 和 AOF 所有的持久化机制
RDB 持久化机制的优缺点
优点
① RDB 会生成多个数据文件,每个数据文件都代表了某一时刻中 redis 的数据,这种多个数据文件的方式,非常适合做冷备,可以将这种完整的数据文件发送到一些远程的安全存储上去,比如说云服务上去,以预定好的备份策略来定期备份 redis 中的数据
RDB 可以做冷备,生成多个文件,每个文件都代表了某一时刻的完整的数据快照;AOF 也可以做冷备,只有一个文件,但是你可以每隔一定时间,去 copy 一份这个文件出来
RDB 做冷备,优势在哪?由 redis 去控制固定时长生成快照文件的事情,比较方便;AOF,还需要自己写一些脚本去做这个事情,各种定时
② RDB 对 redis 对外提供的读写服务,影响非常小,可以让 redis 保持高性能,因为 redis 主进程只需要 fork 一个子进程,让子进程执行磁盘IO 操作来进行 RDB 持久化机制即可
RDB,每次写,都是直接写 redis 内存,只要在一定的时候,才会将数据写入磁盘中
AOF,每次都是要写文件的,虽然可以快速写入 os cache 中,但是还是有一定的时间开销的,速度肯定比 RDB 略慢一些
③ 相对于 AOF 持久化机制来说,直接基于 RDB 数据文件来重启和恢复 redis 进程,更加快速
AOF,存放的指令日志,做数据恢复的时候,其实是要回放和执行所有的指令日志,来恢复出来内存中所有数据的
RDB,就是一份数据文件,恢复的时候,直接加载到内存中即可
结合上述优点,RDB 特别适合做冷备
缺点
① 如果想要在 redis 故障时,尽可能少的丢失数据,那么 RDB 没有 AOF 好,一般来说,RDB 数据快照文件,都是每隔几分钟或者更长时间生成一次,这个时间就得接受一旦 redis 进程宕机,那么会丢失最近几分钟丢失的数据。这个问题也是 rdb 最大的缺点,就是不适合做第一优先的恢复方案,如果你依赖 RDB 做第一优先方案,会导致数据丢失的比较多
② RDB 每次在 fork 子进程的来执行 RDB 快照数据文件生成的时候,如果数据量特别的大,可能会导致对客户端提供的服务暂停一段时间。一般不要让 RDB 的间隔太长,否则每次生成 RDB 文件太大了,对 redis 本身的性能可能会有影响
AOF 持久化的优缺点
优点
① AOF 可以更好的保存数据不丢失,一般 AOF 会每隔 1 秒,通过一个后台线程执行一次 fsync 操作,最多丢失 1 秒钟的数据。
每隔 1 秒钟就执行一次 fsync 操作,可以保证 os cache 中的数据写入磁盘中,redis 进程挂了,最多丢失 1 秒钟的数据
② AOF 日志文件以 append-only 模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复
③ AOF 日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。因为在 rewrite log 的时候,会对其中的指导进行压缩,创造出一份需要恢复数据的最小日志出来。再创建新的文件的时候,老的日志文件还是照常写入,当新的 merge 后的日志文件 ready 的时候,再交换新老日志文件即可
④ AOF 日志文件的命令通过非常可读的方式进行记录,这个特征非常适合做灾难性的误删除的紧急恢复。比如某人不小心用 flushall 命令清空了所有数据,只要这个时候后台 rewrite 还没有发生,那么就可以立刻拷贝到 AOF 文件,将最后一条 flushall 命令给删除,然后再将该 AOF 文件放回去,就可以通过恢复机制,自动恢复所有数据
缺点
① 对于同一份数据来说,AOF 日志文件通常比 RDB 数据快照文件更大
② AOF 开启后,支持的写 QPS 会比 RDB 支持的写 QPS 低,因为 AOF 一般会配置成每秒 fsync 一次日志文件,当然,每秒一次 fsync,性能也还是很高的。如果你要保证一条数据都不丢,也是可以的,AOF 的 fsync 设置成每写入一条数据,fsync一次,那样的话,会使 redis的 QPS 大降
③ 以前 AOF 发生过 bug,就是通过 AOF 记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来。索引说,类似 AOF 这种较为复杂的基于命令日志/merge/回放的方式,比基于 RDB 每次持久化一份完整快照文件的方式,更加脆弱一些,容易有 bug。不过,AOF 就是为了避免 rewrite 过程导致的 bug,因此每次 rewrite 并不是基于旧的的指令日志进行 merge 的,而是通过当时内存中的数据进行指令的重新构建,这样健壮性会好很多
④ 唯一的比较大的缺点,其实就是做数据恢复的时候,会比较慢,还有做冷备份、定期备份不太方便,可能要自己手写复杂的脚本去做,做冷备份不太合适
RDB 和 AOF 如何选择
① 不要仅仅使用 RDB,因为那样会导致你丢失很多数据
② 也不要仅仅使用 AOF,因为那样有两个问题。第一,你通过 AOF 做冷备,没有 RDB 做冷备,来的恢复速度更快;第二,RDB 每次简单粗暴生成数据快照,更加健壮,可能避免 AOF 这种复杂的备份和恢复机制的 bug
③ 综合使用 AOF 和 RDB 两种持久化机制,用 AOF 来保证数据不丢失,作为数据恢复的第一选择;用 RDB 来做不同程度的冷备,在 AOF 文件都丢失或损坏不可用的时候,还可以来进行快速恢复
RDB的原理配置和实验
如何配置 RDB 持久化
在 redis.conf 文件中配置
save 60 1000
# 每隔60s,如果有超过 1000个key发生了变更,那么就生成一个新的 dump.rdb 文件,
# 就是当前 redis 内存中完整的数据快照,这个操作也被称之为 snapshotting,
# 快照也可以手动调用 save 或者 bgsave 命令,同步或异步执行 rdb 快照生成
# save 可以设置多个,就是多个 snapshotting 检查点,没到一个检查点,就会去 check 一下,是否有指定的key数量发生了变更
# 如果有,就生成一个新的 dump.rdb文件
# RDB 持久化配置默认是开启的
RDB 持久化机制的工作流程
① redis 根据配置自己尝试去生成 rdb 快照文件
② fork 一个子进程出来
③ 子进程尝试将数据 dump 到临时的 rdb 快照文件中
④ 完成 rdb 快照文件生成之后,都替换之前旧的快照文件
基于RDB持久化机制的数据恢复实验
- ① 在redis中保存几条数据,立即停掉redis进程,然后重启redis,看看刚才插入的数据还在不在
# 操作如下
[root@xiaoyang init.d]# redis-cli
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> set k2 v2
OK
127.0.0.1:6379> exit
[root@xiaoyang init.d]# redis-cli SHUTDOWN
[root@xiaoyang init.d]# ./redis_6379 start
Starting Redis server...
[root@xiaoyang init.d]# redis-cli
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> get k2
"v2"
# 数据还在,为什么?
# 带出来一个知识点,通过 redis-cli SHUTDOWN 这种方式去停掉 redis,其实是一种安全退出的模式
# redis 在退出的时候会将内存中数据立即生成一份完整的 rdb 快照文件
# /var/redis/6379/dump.rdb
- ② 在redis中再保存几条新的数据,用kill -9粗暴杀死redis进程,模拟redis故障异常退出,导致内存数据丢失的场景
# 操作如下
[root@xiaoyang init.d]# redis-cli
127.0.0.1:6379> set k3 v3
OK
127.0.0.1:6379> set k4 v4
OK
127.0.0.1:6379> exit
[root@xiaoyang init.d]# ps -ef | grep redis
root 8439 1 0 07:45 ? 00:00:00 /usr/local/bin/redis-server 127.0.0.1:6379
root 8484 8407 0 07:55 pts/0 00:00:00 grep --color=auto redis
[root@xiaoyang init.d]# kill -9 8439
[root@xiaoyang init.d]# rm -rf /var/run/redis_6379.pid
[root@xiaoyang init.d]# ./redis_6379 start
Starting Redis server...
[root@xiaoyang init.d]# redis-cli
127.0.0.1:6379> get k3
(nil)
127.0.0.1:6379> get k4
(nil)
# 这次就发现,redis进程异常被杀掉,数据没有 dump 文件,几条最新的数据就丢失了
- ③ 手动设置一个save检查点,save 5 1,写入几条数据,等待5秒钟,会发现自动进行了一次dump rdb快照,在dump.rdb中发现了数据,异常停掉redis进程,再重新启动redis,看刚才插入的数据还在
# 操作如下
127.0.0.1:6379> set aaa bbb
OK
127.0.0.1:6379> set ccc ddd
OK
127.0.0.1:6379> exit
[root@xiaoyang init.d]# rm -rf /var/run/redis_6379.pid
[root@xiaoyang init.d]# ./redis_6379 start
Starting Redis server...
[root@xiaoyang init.d]# redis-cli
127.0.0.1:6379> get aaa
"bbb"
127.0.0.1:6379> get ccc
"ddd"
AOF 原理配置和实验
AOF 持久化配置
AOF 默认是关闭的,需要手动打开配置
在 redis.conf 文件中,更改如下配置
appendonly yes
# appendonly yes,可以打开 AOF 持久化机制
# 在生产环境里面,一般来说 AOF 都是要打开的,除非说随便丢个几分钟数据也无所谓
# 打开 AOF 持久化机制之后,redis 每次接收到一条写命令,就会写入日志文件中,但是会先写入 os cache 中,然后每隔一定时间(根据所设定的策略来定)再 fsync 到文件
# 而且即使 AOF 和 RDB 都开启了,redis重启的时候,也是优先通过 AOF 进行数据恢复的,因为 AOF 数据比较完整
redis AOF 三大策略
# 每次写入一条数据就 fsync,性能非常低,可以保证一条数据不丢
appendfsync always
# 没隔一秒钟执行一次 fsync,常用,默认,生产环境使用的这种
appendfsync everysec
# 仅仅redis负责将数据写入os cache就撒手不管了,然后后面os自己会时不时有自己的策略将数据刷入磁盘,不可控了
appendfsync no
AOF rewrite
redis中的数据其实有限的,很多数据可能会自动过期,可能会被用户删除,可能会被redis用缓存清除的算法清理掉。redis中的数据会不断淘汰掉旧的,就一部分常用的数据会被自动保留在redis内存中。所以可能很多之前的已经被清理掉的数据,对应的写日志还停留在AOF中,AOF日志文件就一个,会不断的膨胀,到很大很大。AOF会自动在后台每隔一定时间做rewrite操作,比如日志里已经存放了针对100w数据的写日志了; redis内存只剩下10万; 基于内存中当前的10万数据构建一套最新的日志,到AOF中; 覆盖之前的老日志; 确保AOF日志文件不会过大,保持跟redis内存数据量一致
redis2.4之前,还需要手动,开发一些脚本,通过BGREWRITEAOF命令去执行AOF rewrite,但是redis2.4之后,会自动进行rewrite操作
在redis.conf中,可以配置rewrite策略
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 比如说上一次AOF rewrite之后,是128mb
# 然后就会接着128mb继续写AOF的日志,如果发现增长的比例,超过了之前的100%,256mb,就可能会去触发一次rewrite
# 但是此时还要去跟min-size,64mb去比较,256mb > 64mb,才会去触发rewrite
- redis fork一个子进程
- 子进程基于当前内存中的数据,构建日志,开始往一个新的临时的AOF文件中写入日志
- redis主进程,接收到client新的写操作之后,在内存中写入日志,同时新的日志也继续写入旧的AOF文件
- 子进程写完新的日志文件之后,redis主进程将内存中的新日志再次追加到新的AOF文件中
- 用新的日志文件替换掉旧的日志文件
AOF破损文件的修复
如果 redis 在 append 数据到 AOF 文件时,机器宕机了,可能会导致 AOF 文件破损,可以用 redis-check-aof --fix 命令来修复破损的 AOF 文件
# 模拟测试
# ① 在 redis 插入几个数据,执行 bgsave 手动生成 appendonly.aof 文件
[root@xiaoyang init.d]# redis-cli
127.0.0.1:6379> set a 1
OK
127.0.0.1:6379> set b 2
OK
127.0.0.1:6379> bgsave
Background saving started
127.0.0.1:6379> exit
[root@xiaoyang init.d]#
# ② 删除几条 appendonly.aof 文件 文件的数据,强制使其破损,其实文件时破损的文件
# ③ 执行以下命令,修复 aof 文件,即删除不完整的数据
[root@xiaoyang 6379]# redis-check-aof --fix appendonly.aof
AOF analyzed: size=70, ok_up_to=50, diff=20
This will shrink the AOF from 70 bytes, with 20 bytes, to 50 bytes
Continue? [y/N]: y
Successfully truncated AOF
[root@xiaoyang 6379]#
# ④ 此时查看文件,发现数据变少了,其实是删除了 aof 文件中不完整的数据
AOF 和 RDB 同时工作
- 如果 RDB 在执行 snapshotting 操作,那么 redis 不会执行 AOF rewrite;如果 redis 再执行 AOF rewrite,那么就不会执行 RDB snapshotting
- 如果 RDB 在执行 snapshotting,此时用户执行 BGREWRITEAOF 命令,那么等 RDB 快照生成之后,才会去执行 AOF rewrite
- 同时有 RDB snapshot 文件和 AOF 日志文件,那么 redis 重启的时候,会优先使用 AOF 进行数据恢复,因为其中的日志更完整
AOF相关的小实验(帮助更好的理解RDB 和 AOF)
# ① 准备,为了更好的模拟出效果,结束 redis 进程,删除 redis_6379.pid,删除 RDB 和 AOF 持久化文件
# ② 为了更好的更快的触发 RDB 重写机制,加上如下策略
save 5 1
# ③ 启动程序,输入如下测试命令,此时变生成了 dump.rdb 文件
[root@xiaoyang init.d]# ./redis_6379 start
Starting Redis server...
[root@xiaoyang init.d]# redis-cli
127.0.0.1:6379> set aaa 111
OK
127.0.0.1:6379> set bbb 222
OK
127.0.0.1:6379> set ccc 333
OK
127.0.0.1:6379> exit
[root@xiaoyang init.d]#
# ④ 结束进程,删除 redis_pid,开启 AOF 持久化机制,注释掉加入的 RDB 策略,重启程序,输入如下测试命令
[root@xiaoyang init.d]# ./redis_6379 start
Starting Redis server...
[root@xiaoyang init.d]# redis-cli
127.0.0.1:6379> set x 123
OK
127.0.0.1:6379> set y 456
OK
127.0.0.1:6379> set z 789
OK
127.0.0.1:6379> exit
# ⑤ 再次结束进程,删除 redis_6379.pid,重启 redis
[root@xiaoyang init.d]# ./redis_6379 start
Starting Redis server...
[root@xiaoyang init.d]# redis-cli
127.0.0.1:6379> get aaa
(nil)
127.0.0.1:6379> get x
"123"
127.0.0.1:6379> get y
"456"
127.0.0.1:6379> get z
"789"
127.0.0.1:6379> get bbb
(nil)
# ⑥ 此时就会发现,redis使用的是 AOF 持久化
# ⑦ 当再次结束进程,并删除 aof 文件,并重启 redis 的时候,发现既不使用 AOF 文件中的数据,也不使用 RDB 文件中的数据
[root@xiaoyang init.d]# ./redis_6379 start
Starting Redis server...
[root@xiaoyang init.d]# redis-cli
127.0.0.1:6379> get aaa
(nil)
127.0.0.1:6379> get bbb
(nil)
127.0.0.1:6379> get x
(nil)
# ⑧ 此时要使用 RDB 文件中的缓存数据,该怎么办呢?
# ⑨ 结束进程,关闭 redis.conf 文件中的 aof 持久化配置,重启redis,这时惊奇的发现,RDB 文件中的缓存又可以用了
[root@xiaoyang init.d]# ./redis_6379 start
Starting Redis server...
[root@xiaoyang init.d]# redis-cli
127.0.0.1:6379> get aaa
"111"
127.0.0.1:6379> get bbb
"222"
127.0.0.1:6379> get x
(nil)
127.0.0.1:6379>
总结,redis 恢复,优先考虑的是 AOF,因为 AOF 文件中的数据完整些;若要使用 RDB 文件中的缓存数据,则需要关闭 redis.conf 配置文件中的 AOF 持久化机制
标签:AOF,127.0,持久,0.1,redis,6379,RDB,化机制 来源: https://www.cnblogs.com/xiaoyangabc/p/16299753.html