Redis的AOF持久化、重写机制、RDB持久化、混合持久化
1、AOF持久化
1.1.AOF持久化大致过程
概括:命令追加(append)、文件写入、文件同步(sync)
Redis 每执行一条写操作命令,就把该命令以追加的方式写入到一个文件里,然后重启 Redis 的时候,先去读取这个文件里的命令,并且执行它,于是恢复了缓存数据。
分析:AOF持久化过程中先执行写操作命令后,再写日志好处和坏处。
好处:1.避免额外的检查开销。2.不会阻塞当前写操作命令的执行。
坏处:1.还未写入磁盘的这个数据就会有丢失的风险。2.可能会给「下一个」命令带来阻塞风险。(原因是因为将命令写入到日志的这个操作和执行命令都是在主进程。也就是说这两个操作是同步的。)
1.2.AOF文件里记录什么
1.3.三种写入磁盘的策略
写入磁盘的大致过程:
-
每次写操作命令执行完后,会将命令追加到 server.aof_buf 缓冲区。
-
然后通过 write() 系统调用,将 aof_buf 缓冲区的数据写入到 AOF 文件的内存缓冲区。
-
至于何时将内存缓冲区的数据写入磁盘,即.aof文件。由各自的策略决定。
补充:操作系统默认是等到缓冲区的空间被填满、或者超过了指定的时限之后, 才真正地将缓冲区中的数据写入到磁盘里面。这种做法虽然提高了效率, 但也为写入数据带来了安全问题, 因为如果计算机发生停机, 那么保存在内存缓冲区里面的写入数据将会丢失。因此系统提供了 fsync 和 fdatasync 两个同步函数, 它们可以强制让操作系统立即将缓冲区中的数据写入到硬盘里面, 从而确保写入数据的安全性。
1.3.1.Always
每次写操作命令执行完后,会将命令追加到 server.aof_buf 缓冲区。将 aof_buf
缓冲区中的所有内容写入到 AOF 文件, 并同步将 AOF 日志数据写入硬盘;
从安全性来说, always
也是最安全的, 因为即使出现故障停机, AOF 持久化也只会丢失一个事件循环中所产生的命令数据。
从效率上说,效率慢。因为写入磁盘的过程也是在主线程完成的。
1.3.2.Everysec
每次写操作命令执行完后,会将命令追加到 server.aof_buf 缓冲区。将 aof_buf
缓冲区中的所有内容写入到 AOF 文件, 并且每隔超过一秒就要在子线程中对 AOF 文件进行一次同步。
从效率上来讲, everysec
模式足够快, 并且就算出现故障停机, 数据库也只丢失一秒钟的命令数据。
1.3.3.No
每次写操作命令执行完后,会将命令追加到 server.aof_buf 缓冲区。将 aof_buf
缓冲区中的所有内容写入到 AOF 文件, 至于何时对 AOF 文件进行同步, 则由操作系统控制。
从效率上来讲,因为无须执行同步操作, 所以该模式下的 AOF 文件写入速度总是最快的。
1.4.AOF 重写机制
1.4.1.AOF 重写机制过程
-
为了解决AOF文件过大的问题,于是引入AOF重写机制。
-
重写机制是通过 fork 出一个子进程来完成的,子进程会扫描 Redis 的数据库,读取每个键的值,用一条命令代替原来的多条命令。然后写入到一个新的AOF文件中。
-
在子进程进行 AOF 重写的过程中,主进程还会继续接收和处理客户端的请求,如果有新的写操作发生,主进程会将这些写操作追加到一个AOF重写缓冲区和AOF缓冲区中。
-
当子进程完成AOF重写工作之后,它会向父进程发送一个信号。
-
父进程在接到该信号之后,会调用一个信号处理函数:将AOF重写缓冲区中的所有内容写入到新AOF文件中;新AOF文件代替现有的AOF文件。
-
完成AOF后台重写。
1.4.2.何时会触发重写机制
-
AOF 重写机制可以由用户手动触发,也可以由系统自动触发 。
-
用户手动触发 AOF 重写机制可以通过执行 BGREWRITEAOF 命令来实现 。
-
系统自动触发 AOF 重写机制可以通过配置文件中的 auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size 参数来控制 。
-
auto-aof-rewrite-percentage 参数表示当当前 AOF 文件大小超过上次重写后 AOF 文件大小的百分比时,触发 AOF 重写机制,默认值为 100 。
-
auto-aof-rewrite-min-size 参数表示当当前 AOF 文件大小超过指定值时,才可能触发 AOF 重写机制,默认值为 64 MB 。
-
系统自动触发 AOF 重写机制还需要满足以下条件 :
-
当前没有正在执行 BGSAVE 或 BGREWRITEAOF 的子进程
-
当前没有正在执行 SAVE 的主进程
-
1.4.3.补充的点
-
aof_rewrite函数可以很好地完成创建一个新AOF文件的任务并进行大量的写入操作,所以调用这个函数的线程将被长时间阻塞,因为Redis服务器使用单个线程来处理命令请求,所以如果由服务器直接调用aof_rewrite函数的话,那么在重写AOF文件期间,服务期将无法处理客户端发来的命令请求。因此选择开启子进程进行AOF重写。
-
fork的过程:把主进程的页表复制一份给子进程,而不会复制物理内存,此时主进程和子进程都共享物理内存。
-
当主进程修改内存页之前,会复制一个该页的副本,并将其分配给执行写操作的进程。而子进程仍然共享未修改的物理内存页。这个过程叫做写时复制。
-
写入AOF缓冲区是为了对现有AOF文件的处理工作会如常进行。
-
在AOF重写过程中,只有fork页表、写时复制、信号处理函数会影响主线程。在其他时候,AOF 后台重写都不会阻塞主进程。
2、RDB持久化
2.1.RDB持久化过程
-
执行save或bgsave命令,生成RDB文件。save和bgsave区别在于是否在主线程生成RDB文件。
-
执行 bgsave 命令的时候,会在子进程中生产RDB文件。通过 fork() 创建子进程,此时子进程和父进程是共享同一片物理内存。
-
当主进程要进行写操作时,就会写时复制。而主线程刚修改的数据,是没办法在这一时间写入 RDB 文件的,RDB 文件保存的是原本的内存数据。只能交由下一次的 bgsave 生产RDB文件。
-
服务器启动时就会自动执行RDB文件的加载。
2.2.何时进行RDB持久化
Redis 通过配置文件的选项来实现每隔一段时间自动执行一次 bgsave 命令,默认会提供以下配置:
save 900 1 save 300 10 save 60 10000
只要满足上面条件的任意一个,就会执行 bgsave,它们的意思分别是:
900 秒之内,对数据库进行了至少 1 次修改;
300 秒之内,对数据库进行了至少 10 次修改;
60 秒之内,对数据库进行了至少 10000 次修改。
以上分析,
RDB持久化和AOF持久化都有各自的优点:执行RDB文件数据恢复更快。而AOF文件能确保数据丢失少。毕竟人家是执行一条写操作就记录到AOF文件中。而RDB文件是隔一段时间才进行全量写入。
3、Redis 混合持久化
3.1.混合持久化过程
-
混合持久化工作在 AOF 日志重写过程。
-
在AOF重写过程中,fork出的子进程,以RDB的方式写入AOF文件中。
-
期间主进程进行的写操作记录在AOF重写缓冲区中。当子进程执行重写完成后,父进程将AOF重写缓冲区中的所有内容写入以AOF方式写入AOF文件。
-
这样,AOF 文件的前半部分是 RDB 格式的全量数据,后半部分是 AOF 格式的增量数据。
-
重启 Redis 加载数据的时候,由于前半部分是 RDB 内容,这样加载的时候速度会很快。
-
混合持久化的优点是:
-
可以减少 AOF 文件的大小,节省磁盘空间
-
可以加快数据恢复的速度,避免执行大量的 AOF 命令
-
可以避免数据丢失,因为 RDB 文件和 AOF 文件都有最新的数据快照
-
3.2.如何开启混合持久化
-
要开启混合持久化,需要在 redis.conf 文件中设置以下参数:
-
appendonly yes
开启 AOF 持久化 -
aof-use-rdb-preamble yes
开启混合持久化
-
4、Redis的内存大key的对持久化的影响
-
写入磁盘策略如果是Always,那么在调用fsync同步函数写入磁盘的时间就会变长,对主线程有一定的阻塞。
-
在AOF重写过程、RDB持久化过程中,fork页表时、写时复制耗时都会变长,从而影响主线程。