持久化
参考:小林 coding
参考视频
AOF
Append Ony File,是一个文本文件,因此较大。 当客户端发起一个写请求时,Redis 主线程首先在内存中执行写操作,接着将这个写命令同步到磁盘中的 AOF 日志中。
AOF的优点
- 先在内存中执行写命令,再写回磁盘。这样可以确保命令是正确的,才记录在日志中,也可以防止写回磁盘的操作阻塞当前写操作。
如何配置AOF?
AOF默认不开启,需要更改Redis的配置文件。 /opt/homebrew/etc/redis.conf
|
|
写回策略
- appendfsync always:每次写请求完成,把这条写命令写入磁盘的日志中。数据最安全,但是频繁磁盘IO影响性能。如果对数据完整性要求极高,比如金融交易平台,则会选择这种策略。
- appendfsync everysec🌟:每次写请求完成,把写命令写入到内核缓冲区中,然后每秒钟,内核缓存区调用一次fsynch(),把数据写入磁盘。
- appendfsync no: 不主动写回。等待操作系统把命令写入磁盘中。系统崩溃或断电时会丢失大量未同步数据。
AOF重写
AOF文件可能会过大,因此当文件大于64M时,就会 通过重写来压缩文件体积。
- fork一个子进程bgrewriteaof来遍历数据库中所有的key-value pair, 为每一个pair生成一条命令,写入一个新的AOF文件。
- 在这个过程中,主线程一边处理客户端发来的请求,一边把命令追加进AOF缓冲区和AOF重写缓冲区。
- 当子进程完成重写后,主进程会将 AOF 重写缓冲区中的增量数据追加到新 AOF 文件中。最后用新AOF日志代替旧AOF日志。
为什么重写需要一个新的AOF文件?
如果重写失败,则会污染现有的AOF文件。
为什么用子进程,而不是子线程?
因为线程会共享内存,需要加锁来保证两个线程对内存的操作互不影响。但是子进程可以利用写时复制的特点,保证两个进程的物理内存分开。
AOF重写缓冲区
重写期间的新写命令会写入 AOF 重写缓冲区,确保数据不丢失。
重写会阻塞主线程吗?
写时复制时会阻塞主线程;当子进程遍历完 pair之后,会发给主进程一个signal,主进程会执行signal handler,将AOF重写缓冲区的命令追加到新AOF文件中。在执行handler时也会阻塞。
RDB
RDB是一个二进制文件,对此时内存中的全量数据做一个快照。主进程fork一个子进程,子进程来将内存写在临时RDB文件中。
与此同时,主进程继续处理新的写操作,但它并不是在原来的物理内存上操作,因为写时复制的机制,它在OS复制出来的内存副本上执行写操作。
优点:性能高,因为恢复数据时,能以二进制的形式加载。 文件小。
缺点:可能会丢失数据。因为每次备份具有时间间隔,如果在两次备份之间出现了宕机,那么会丢失数据。
配置
save 300 10
实际上执行的是bgsave命令,也就是 fork 子进程,让子进程生成快照。
代表 300 秒内至少有 10 次数据库的改动时,会触发一次备份。备份不能太频繁,因为全量快照开销大,每秒备份会影响数据库性能。
RDB & AOF 混合
混合持久化。
在AOF重写阶段,主进程fork出一个子进程。子进程此时为数据库生成一个RDB快照,写入新AOF文件中。该文件的开头是RDB格式,后面是AOF命令格式。
与此同时,主进程也在处理客户端请求,它会把这段时间的写请求追加在重写缓存区和AOF缓存区。
等子进程工作完毕,主进程就将重写缓存区中的命令追加到新的AOF文件中。最后,用新文件替换旧文件。
配置:aof-use-rdb-preamble yes