关于Redis持久化,你了解多少?(下)-内含整理资料

  • Post author:
  • Post category:其他


原文地址:





关于Redis持久化,你了解多少?(下)-内含整理资料






AOF(append-only-file),通过保存执行命令来记录数据库状态

AOF的配置

# 是否开启aof
appendonly yes

# 文件名称
appendfilename "appendonly.aof"

# 同步方式
appendfsync everysec

# aof重写期间是否同步
no-appendfsync-on-rewrite no

# 重写触发配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# 加载aof时如果有错如何处理
aof-load-truncated yes

# 文件重写策略
aof-rewrite-incremental-fsync yes


复制代码还是重点解释一些关键的配置:

appendfsync everysec

它其实有三种模式:

  • always:把每个写命令都立即同步到aof,很慢,但是很安全
  • everysec:每秒同步一次,是折中方案
  • no:redis不处理交给OS来处理,非常快,但是也最不安全

一般情况下都采用

everysec

配置,这样可以兼顾速度与安全,最多损失1s的数据。

aof-load-truncated yes

如果该配置启用,在加载时发现aof尾部不正确是,会向客户端写入一个log,但是会继续执行,如果设置为

no

,发现错误就会停止,必须修复后才能重新加载。

开启AOF

将 redis.conf 的 appendonly 配置改为yes 即可。AOF 保存文件的位置和 RDB 保存文件的位置一样,都是通过redis.conf 配置文件的 dir 配置:可以通过 config get dir 命令获取保存的路径。

AOF重写

由于AOF持久化是Redis不断将写命令记录到AOF 文件中,随着Redis不断的进行,AOF 的文件会越来越大,文件越大,占用服务器内存越大以及AOF

恢复要求时间越长。为了解决这个问题,Redis新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。可以使用命令bgrewriteaof 来重新。

如果不进行 AOF 文件重写,那么 AOF 文件将保存四条 SADD

命令,如果使用AOF 重写,那么AOF 文件中将只会保留下面一条命令:

sadd animals "dog" "tiger" "panda" "lion" "cat"

也就是说 AOF 文件重写并不是对原文件进行重新整理,而是直接读取服务器现有的键值对,然后用一条命令去代替之前记录这个键值对的多条命令,生成一个新的文件后去替换原来的 AOF 文件。

AOF 文件重写触发机制:通过 redis.conf

配置文件中的 auto-aof-rewrite-percentage:默认值为100,以及auto-aof-rewrite-min-size:64mb

配置,也就是说默认Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。

这里再提一下,我们知道 Redis 是单线程工作,如果 重写 AOF

需要比较长的时间,那么在重写 AOF 期间,Redis将长时间无法处理其他的命令,这显然是不能忍受的。Redis为了克服这个问题,解决办法是将 AOF

重写程序放到子程序中进行,这样有两个好处:

①、子进程进行 AOF

重写期间,服务器进程(父进程)可以继续处理其他命令。

②、子进程带有父进程的数据副本,使用子进程而不是线程,可以在避免使用锁的情况下,保证数据的安全性。

使用子进程解决了上面的问题,但是新问题也产生了:因为子进程在进行

AOF 重写期间,服务器进程依然在处理其它命令,这新的命令有可能也对数据库进行了修改操作,使得当前数据库状态和重写后的 AOF 文件状态不一致。

为了解决这个数据状态不一致的问题,Redis 服务器设置了一个 AOF

重写缓冲区,这个缓冲区是在创建子进程后开始使用,当Redis服务器执行一个写命令之后,就会将这个写命令也发送到 AOF 重写缓冲区。当子进程完成 AOF

重写之后,就会给父进程发送一个信号,父进程接收此信号后,就会调用函数将 AOF 重写缓冲区的内容都写到新的 AOF 文件中。

这样将 AOF 重写对服务器造成的影响降到了最低。

AOF的原理


AOF的整个流程大体来看可以分为两步,一步是命令的实时写入(如果是

appendfsync everysec

配置,会有

1s

损耗),第二步是对aof文件的重写。

对于增量追加到文件这一步主要的流程是:

命令写入=>追加到aof_buf =>同步到aof磁盘

。那么这里为什么要先写入buf在同步到磁盘呢?如果实时写入磁盘会带来非常高的磁盘IO,影响整体性能。

aof重写是为了减少aof文件的大小,可以手动或者自动触发,关于自动触发的规则请看上面配置部分。fork的操作也是发生在重写这一步,也是这里会对主进程产生阻塞。

手动触发:

bgrewriteaof

,自动触发 就是根据配置规则来触发,当然自动触发的整体时间还跟Redis的定时任务频率有关系。

下面来看看重写的一个流程图:


对于上图有四个关键点补充一下:

在重写期间,由于主进程依然在响应命令,为了保证最终备份的完整性;因此它依然会写入旧的AOF file中,如果重写失败,能够保证数据不丢失。

为了把重写期间响应的写入信息也写入到新的文件中,因此也会为子进程保留一个buf,防止新写的file丢失数据。

重写是直接把当前内存的数据生成对应命令,并不需要读取老的AOF文件进行分析、命令合并。

AOF文件直接采用的文本协议,主要是兼容性好、追加方便、可读性高可认为修改修复。

不能是RDB还是AOF都是先写入一个临时文件,然后通过 rename 完成文件的替换工作。

AOF的优缺点

优点:

①、AOF持久化的方法提供了多种的同步频率,即使使用默认的同步频率每秒同步一次,Redis 最多也就丢失 1 秒的数据

②、AOF 文件使用 Redis 命令追加的形式来构造,因此,即使Redis 只能向 AOF 文件写入命令的片断,使用 redis-check-aof 工具也很容易修正AOF 文件。

③、AOF文件的格式可读性较强,这也为使用者提供了更灵活的处理方式。例如,如果我们不小心错用了 FLUSHALL 命令,在重写还没进行时,我们可以手工将最后的FLUSHALL 命令去掉,然后再使用 AOF 来恢复数据。

缺点:

①、对于具有相同数据的的 Redis,AOF 文件通常会比 RDF文件体积更大。

②、虽然 AOF提供了多种同步的频率,默认情况下,每秒同步一次的频率也具有较高的性能。但在 Redis 的负载较高时,RDB 比 AOF 具好更好的性能保证。

③、RDB 使用快照的形式来持久化整个 Redis 数据,而 AOF只是将每次执行的命令追加到 AOF 文件中,因此从理论上说,RDB 比 AOF 方式更健壮。官方文档也指出,AOF 的确也存在一些 BUG,这些 BUG 在RDB 没有存在。

AOF和RDB如何选择?

在线上我们到底该怎么做?我提供一些自己的实践经验。

  • 如果Redis中的数据并不是特别敏感或者可以通过其它方式重写生成数据,可以关闭持久化,如果丢失数据可以通过其它途径补回;
  • 自己制定策略定期检查Redis的情况,然后可以手动触发备份、重写数据;
  • 单机如果部署多个实例,要防止多个机器同时运行持久化、重写操作,防止出现内存、CPU、IO资源竞争,让持久化变为串行;
  • 可以加入主从机器,利用一台从机器进行备份处理,其它机器正常响应客户端的命令;
  • RDB持久化与AOF持久化可以同时存在,配合使用。


5.0.5版本中,如果同时开启RDB和AOF进行持久化,在重启Redis时,只会加载AOF文件!!!



关于Redis持久化,你了解多少?(上)-内含整理资料



做不到这几点,你算什么合格的技术面试官啊?!



高频面试考点:LRU缓存淘汰算法



如何构建自己的知识体系?



版权声明:本文为qq_33017925原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。