Redis 数据持久化

Posted by 彭楷淳 on 2021-01-26
Estimated Reading Time 9 Minutes
Words 2.5k In Total
Viewed Times

Redis 持久化


整体上来说,Redis 持久化有两种方式,快照持久化和 AOF ,在项目中我们可以根据实际情况选择合适的持久化方式,也可以不用持久化,这关键看我们的 Redis 在项目中扮演了什么样的角色。

快照持久化


快照持久化,顾名思义,就是通过拍摄快照的方式实现数据的持久化,redis 可以在某个时间点上对内存中的数据创建一个副本文件,副本文件中的数据在 redis 重启时会被自动加载,我们也可以将副本文件拷贝到其他地方一样可以使用。

如何配置快照持久化

redis中的快照持久化默认是开启的,redis.conf中相关配置主要有如下几项:

1
2
3
4
5
6
7
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
dbfilename dump.rdb
dir ./

前面三个 save 相关的选项表示备份的频率,分别表示 900 秒内至少一个键被更改则进行快照,300 秒内至少 10 个键被更改则进行快照,60 秒内至少 10000 个键被更改则进行快照, stop-writes-on-bgsave-error 表示在快照创建出错后,是否继续执行写命令, rdbcompression 则表示是否对快照文件进行压缩, dbfilename 表示生成的快照文件的名字,dir 则表示生成的快照文件的位置,在 redis 中,快照持久化默认就是开启的。我们可以通过如下步骤验证快照持久化的效果:

  1. 进入 redis 安装目录,如果有 dump.rdb 文件,先将之删除。

  2. 启动 redis ,随便向 redis 中存储几个数据,然后关闭redis并退出,如下:

1
2
3
4
5
6
7
8
[root@localhost redis-4.0.8]## redis-server redis.conf
[root@localhost redis-4.0.8]## 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> SHUTDOWN
not connected> exit
  1. 退出来后,我们发现刚刚删掉的 dump.rdb 文件又回来了,这就是生成的备份文件。
  2. 此时再次启动 redis 并进入,发现刚刚存储的数据都还在,这是因为 redis 在启动时加载了 dump.rdb 中的数据。好了,关闭 redis 并退出。
  3. 将 redis 目录下的 dump.rdb 文件删除。
  4. 再次启动 redis 并进入到控制台,所有的数据都不存在了。

快照持久化操作流程

通过上面的介绍,小伙伴们对快照持久化都有一个大致的认识了,那么这个东西到底是怎么运行的?持久化的时机是什么?我们来仔细扒一扒。

  1. 在 redis 运行过程中,我们可以向 redis 发送一条 save 命令来创建一个快照,save 是一个阻塞命令,redis 在接收到 save 命令之后,开始执行备份操作之后,在备份操作执行完毕之前,将不再处理其他请求,其他请求将被挂起,因此这个命令我们用的不多。save 命令执行如下:

    1
    2
    127.0.0.1:6379> save
    OK
  2. 在 redis 运行过程中,我们也可以发送一条 bgsave 命令来创建一个快照,不同于 save 命令,bgsave 命令会 fork 一个子进程,然后这个子进程负责执行将快照写入硬盘,而父进程则继续处理客户端发来的请求,这样就不会导致客户端命令阻塞了。如下:

    1
    2
    127.0.0.1:6379> bgsave
    Background saving started
  3. 如果我们在 redis.conf 中配置了如下选项:

    1
    2
    3
    save 900 1
    save 300 10
    save 60 10000

    那么当条件满足时,比如 900 秒内有一个 key 被操作了,那么 redis 就会自动触发 bgsava 命令进行备份。我们可以根据实际需求在 redis.conf 中配置多个这种触发规则。

还有一种情况也会触发 save 命令,那就是我们执行 shutdown 命令时,当我们用 shutdown 命令关闭 redis 时,此时也会执行一个 save 命令进行备份操作,并在备份操作完成后将服务器关闭。

最后还有一种特殊情况也会触发 bgsave 命令,就是在主从备份的时候。当从机连接上主机后,会发送一条 sync 命令来开始一次复制操作,此时主机会开始一次 bgsave 操作,并在 bgsave 操作结束后向从机发送快照数据实现数据同步。

快照持久化的缺点

快照持久化有一些缺点,比如 save 命令会发生阻塞,bgsave 虽然不会发生阻塞,但是 fork 一个子进程又要耗费资源,在一些极端情况下,fork 子进程的时间甚至超过数据备份的时间。定期的持久化也会让我们存在数据丢失的风险,最坏的情况我们可能丢失掉最近一次备份到当下的数据,具体丢失多久的数据,要看我们项目的承受能力,我们可以根据项目的承受能力配饰 save 参数。

AOF 持久化


与快照持久化不同,AOF 持久化是将被执行的命令写到 aof 文件末尾,在恢复时只需要从头到尾执行一遍写命令即可恢复数据,AOF 在 redis 中默认也是没有开启的,需要我们手动开启,开启方式如下:

打开 redis.conf 配置文件,修改 appendonly 属性值为 yes ,如下:

1
appendonly yes

另外几个和 AOF 相关的属性如下:

1
2
3
4
5
6
7
appendfilename "appendonly.aof"
# appendfsync always
appendfsync everysec
# appendfsync no
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

这几个属性的含义分别如下:

  1. appendfilename 表示生成的 AOF 备份文件的文件名。
  2. appendfsync 表示备份的时机,always 表示每执行一个命令就备份一次,everysec 表示每秒备份一次,no 表示将备份时机交给操作系统。
  3. no-appendfsync-on-rewrite 表示在对 aof 文件进行压缩时,是否执行同步操作。
  4. 最后两行配置表示 AOF 文件的压缩时机,这个我们一会再细说。

同时为了避免快照备份的影响,我们将快照备份关闭,关闭方式如下:

1
2
3
4
save ""
# save 900 1
# save 300 10
# save 60 10000

此时,当我们在 redis 中进行数据操作时,就会自动生成 AOF 的配置文件 appendonly.aof。注意,此时没有 dump.rdb 文件,这时我们将 redis 关闭并重启,会发现之前的数据都还在,这就是 AOF 备份的结果。

AOF 备份的几个关键点

1.通过上面的介绍,小伙伴们了解到 appendfsync 的取值一共有三种,我们在项目中首选 everysec,always 选项会严重降低 redis 性能。
2.使用 everysec ,最坏的情况下我们可能丢失1秒的数据。

AOF 文件的重写与压缩

AOF 备份有很多明显的优势,当然也有劣势,那就是文件大小。随着系统的运行,AOF 的文件会越来越大,甚至把整个电脑的硬盘填满,AOF 文件的重写与压缩机制可以在一定程度上缓解这个问题。
当 AOF 的备份文件过大时,我们可以向 redis 发送一条 bgrewriteaof 命令进行文件重写,如下:

1
2
3
127.0.0.1:6379> bgrewriteaof
Background append only file rewriting started
(0.71s)

bgrewriteaof 的执行原理和我们上文说的 bgsave 的原理一致,这里我就不再赘述,因此 bgsave 执行过程中存在的问题在这里也一样存在。

bgrewriteaof 也可以自动执行,自动执行时间则依赖于 auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size 配置,auto-aof-rewrite-percentage 100 表示当目前 aof 文件大小超过上一次重写时的 aof 文件大小的百分之多少时会再次进行重写,如果之前没有重写,则以启动时的 aof 文件大小为依据,同时还要求 AOF 文件的大小至少要大于 64M(auto-aof-rewrite-min-size 64mb)。

最佳实践

  1. 如果 redis 只做缓存服务器,那么可以不使用任何持久化方式。
  2. 同时开启两种持久化方式,在这种情况下,当 redis 重启的时候会优先载入 AOF 文件来恢复原始的数据, 因为在通常情况下 AOF 文件保存的数据集要比 RDB 文件保存的数据集要完整;RDB 的数据不完整时,同时使用两者时服务器重启也只会找 AOF 文件。那要不要只使用 AOF 呢? 作者建议不要,因为 RDB 更适合用于备份数据库( AOF 在不断变化不好备份), 快速重启,而且不会有 AOF 可能潜在的 bug ,留着作为一个万一的手段。
  3. 因为 RDB 文件只用作后备用途,建议只在 slave 上持久化 RDB 文件,而且只要 15 分钟备份一次就够了,只保留 save 900 1 这条规则。
  4. 如果 Enalbe AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只 load 自己的 AOF 文件就可以了。代价一是带来了持续的 IO,二是 AOF rewrite 的最后将 rewrite 过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少 AOF rewrite 的频率,AOF 重写的基础大小默认值 64M 太小了,可以设到 5G 以上。默认超过原大小 100% 大小时重写可以改到适当的数值。
  5. 如果不 Enable AOF ,仅靠 Master-Slave Replication 实现高可用性也可以。能省掉一大笔 IO 也减少了 rewrite 时带来的系统波动。代价是如果 Master/Slave 同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个 Master/Slave 中的 RDB 文件,载入较新的那个。

Redis 数据持久化就介绍这么多,更多资料可以参考官方文档

更多干货请移步:https://antoniopeng.com


If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !