上一篇介绍了 Redis 实现消息队列的三种方式。这节开始介绍 Redis 的持久化问题。
我们都知道 Redis 是基于内存的数据库,而内存又是易失性的,一旦遇到断电或异常重启等问题时,内存中的数据就会丢失。所以 Redis 为了保证数据的可靠性花了不少功夫。Redis 主要是通过 AOF 日志和 RDB 快照来实现持久化的。
Redis 共有三种数据持久化的方式:
Append Only File,Redis 每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里。默认关闭。
AOF 是写后日志,即先执行命令把数据写入内存,再记录日志。(大多数据库采用的是写前日志 WAL(Write Ahead Logging),如 MySQL)
Redis 要求高性能,采用写后日志有两方面好处:
但是存在两个风险:
server.aof_buf
缓冲区(AOF 缓冲区);Redis 提供了 3 种写回硬盘的策略,控制的就是流程的第三步。在 redis.conf
配置文件中的 appendfsync
配置项可以有以下 3 种参数可填:
AOF 日志是一个文件,随着执行的写操作命令越来越多,文件的大小会越来越大(大部分是无用的历史数据),会带来性能问题。
AOF 是记录每次操作的命令,即使有了重写机制,也会非常大,且在恢复数据时需要一条条重放命令,非常缓慢。
当 AOF 文件的大小超过所设定的阈值后,Redis 就会启用 AOF 重写机制,来压缩 AOF 文件。
AOF 重写机制是在重写时,读取当前数据库中的所有键值对,然后将每一个键值对用一条命令记录到「新的 AOF 文件」,等到全部记录完后,就将新的 AOF 文件替换掉现有的 AOF 文件。
重写 AOF 过程是由后台子进程 bgrewriteaof 来完成的,这么做有两个好处:
在重写 AOF 日志过程中,如果主进程修改了已经存在的数据,就会导致主进程和子进程中的数据不一致。所以 Redis 设置了一个 AOF 重写缓冲区,这个缓冲区在创建 bgrewriteaof 子进程之后开始使用。在重写 AOF 期间,当 Redis 执行完一个写命令之后,它会同时将这个写命令写入到 「AOF 缓冲区」和 「AOF 重写缓冲区」。
每条写命令是先写入 AOF 缓冲区,再集中写入到内核缓冲区之后进行刷盘的;而 AOF 重写缓冲区是用于记录在 AOF 重写时新的写命令,之后需要追加到新的 AOF 文件中。所以需要将同一个写命令写入到两个缓冲区中去。
当子进程完成 AOF 重写工作后,会向主进程发送一条信号,信号是进程间通讯的一种方式,且是异步的。
主进程收到该信号后,会调用一个信号处理函数,该函数主要做以下工作:
在 AOF 重写时,Redis 实例仍然会调用后台线程进行 fsync 操作(即使写回策略为 no),将新的 AOF 文件写入磁盘。
为什么重写 AOF 的时候,不直接复用现有的 AOF 文件,而是先写到新的 AOF 文件再覆盖过去?
父子进程写同一个文件会产生竞争问题,影响父进程的性能。
因为如果 AOF 重写过程中失败了,现有的 AOF 文件就会造成污染,可能无法用于恢复使用。
在重写日志的整个过程中,主线程会被阻塞的时候有:
Redis Database,即快照/内存快照,RDB 快照就是记录某一个瞬间的内存数据,记录的是实际数据(二进制数据,使用 LZF 算法进行压缩),因此在 Redis 恢复数据时, RDB 恢复数据的效率会比 AOF 高些,因为直接将 RDB 文件读入内存就可以,不需要像 AOF 那样还需要额外执行操作命令的步骤才能恢复数据。
Redis 提供了两个命令来生成 RDB 文件,分别是 save
和 bgsave
,他们的区别就在于是否在「主线程」里执行:
Redis 还可以通过配置文件的选项来实现每隔一段时间自动执行一次 bgsave 命令。
# 在配置文件中使用如”save m n”,表示m秒内数据修改n次,自动触发bgsave。
save 900 1
save 300 10
save 60 10000
在执行
debug reload
命令重新加载 Redis,会自动触发 save 操作。在执行shutdown
命令时,没有开启 AOF 持久化会自动执行 bgsave。
在子进程生成 RBD 文件时,使用了写时复制技术,主线程还是可以工作的。
在整个过程中,只有在 fork 子进程时,需要拷贝虚拟页表,主线程会被阻塞。
Redis 的快照是全量快照,也就是说每次执行快照,都是把内存中的「所有数据」都记录到磁盘中。所以频繁执行快照会对性能造成影响,而设置的时间过长又会导致部分数据丢失。
RDB 的优点是恢复速度远快于 AOF、占内存空间小;缺点是要用很大的性能才能换取较好的实时性;
RDB 存在两个风险:
Redis 4.0 开始支持混合使用 AOF 日志和内存快照,也叫混合持久化。简单来说就是,内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。
当开启了混合持久化时,在 AOF 重写日志时,重写子进程会先将与主线程共享的内存数据以 RDB 方式写入到 AOF 文件,然后主线程处理的操作命令会被记录在重写缓冲区里,重写缓冲区里的增量命令会以 AOF 方式写入到 AOF 文件,写入完成后通知主进程将新的含有 RDB 格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件。
也就是说,使用了混合持久化,AOF 文件的前半部分是 RDB 格式的全量数据,后半部分是 AOF 格式的增量数据。
这样的好处在于,重启 Redis 加载数据的时候,由于前半部分是 RDB 内容,这样加载的时候速度会很快。
Redis 启动时,会从 AOF 和 RBD 文件中恢复数据,所以如果想要恢复数据,只需重启 Redis 即可。
本文介绍了 Redis 中的实现数据持久化的方案,主要是 AOF 日志和 RDB 快照。下一节将介绍 Redis 的内存管理。
下一篇:【C++】面向对象之继承