redis 持久化的意义,在于故障恢复。
比如说,你部署了一个 redis,作为 cache 缓存,当然也可以保存一些比较重要的数据。如果没有持久化的话,redis遇到灾难性故障的时候,就会丢失所有的数据,如果通过持久化将数据搞一份在磁盘上去,然后定期去同步和备份到一些云存储服务上去,那么就可以保证数据不丢失全部,还是可以恢复一部分数据回来的
① 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 会每隔 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,因为那样有两个问题。第一,你通过 AOF 做冷备,没有 RDB 做冷备,来的恢复速度更快;第二,RDB 每次简单粗暴生成数据快照,更加健壮,可能避免 AOF 这种复杂的备份和恢复机制的 bug
③ 综合使用 AOF 和 RDB 两种持久化机制,用 AOF 来保证数据不丢失,作为数据恢复的第一选择;用 RDB 来做不同程度的冷备,在 AOF 文件都丢失或损坏不可用的时候,还可以来进行快速恢复
在 redis.conf 文件中配置
save 60 1000 # 每隔60s,如果有超过 1000个key发生了变更,那么就生成一个新的 dump.rdb 文件, # 就是当前 redis 内存中完整的数据快照,这个操作也被称之为 snapshotting, # 快照也可以手动调用 save 或者 bgsave 命令,同步或异步执行 rdb 快照生成 # save 可以设置多个,就是多个 snapshotting 检查点,没到一个检查点,就会去 check 一下,是否有指定的key数量发生了变更 # 如果有,就生成一个新的 dump.rdb文件 # RDB 持久化配置默认是开启的
① redis 根据配置自己尝试去生成 rdb 快照文件
② fork 一个子进程出来
③ 子进程尝试将数据 dump 到临时的 rdb 快照文件中
④ 完成 rdb 快照文件生成之后,都替换之前旧的快照文件
# 操作如下 [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
# 操作如下 [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 文件,几条最新的数据就丢失了
# 操作如下 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 默认是关闭的,需要手动打开配置
在 redis.conf 文件中,更改如下配置
appendonly yes # appendonly yes,可以打开 AOF 持久化机制 # 在生产环境里面,一般来说 AOF 都是要打开的,除非说随便丢个几分钟数据也无所谓 # 打开 AOF 持久化机制之后,redis 每次接收到一条写命令,就会写入日志文件中,但是会先写入 os cache 中,然后每隔一定时间(根据所设定的策略来定)再 fsync 到文件 # 而且即使 AOF 和 RDB 都开启了,redis重启的时候,也是优先通过 AOF 进行数据恢复的,因为 AOF 数据比较完整
# 每次写入一条数据就 fsync,性能非常低,可以保证一条数据不丢 appendfsync always # 没隔一秒钟执行一次 fsync,常用,默认,生产环境使用的这种 appendfsync everysec # 仅仅redis负责将数据写入os cache就撒手不管了,然后后面os自己会时不时有自己的策略将数据刷入磁盘,不可控了 appendfsync no
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 在 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 文件中不完整的数据
# ① 准备,为了更好的模拟出效果,结束 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 持久化机制