AOF日志-宕机了如何避免数据丢失

AOF⽇志正好相反,它是写后⽇志,“写 后”的意思是Redis是先执⾏命令,把数据写⼊内存,然后才记录⽇志
好处:

  1. 为了避免额外的检查开销,Redis在向AOF⾥⾯记录⽇志的时候,并不会先去对这些命令进⾏语法检 查。所以,如果先记⽇志再执⾏命令的话,⽇志中就有可能记录了错误的命令,Redis在使⽤⽇志恢复数据 时,就可能会出错。⽽写后⽇志这种⽅式,就是先让系统执⾏命令,只有命令能执⾏成功,才会被记录到⽇志中,否则,系统就 会直接向客⼾端报错。所以,Redis使⽤写后⽇志这⼀⽅式的⼀⼤好处是,可以避免出现记录错误命令的情况。
  2. 它是在命令执⾏后才记录⽇志,所以不会阻塞当前写操作

潜在风险:

  1. 如果刚执⾏完⼀个命令,还没有来得及记⽇志就宕机了,那么这个命令和相应的数据就有丢失的⻛险。
  2. AOF虽然避免了对当前命令的阻塞,但可能会给下⼀个操作带来阻塞⻛险。这是因为,AOF⽇志也是 在主线程中执⾏的,如果在把⽇志⽂件写⼊磁盘时,磁盘写压⼒⼤,就会导致写盘很慢,进⽽导致后续的操作也⽆法执⾏了。

三种写策略

AOF机制给我们提供了三个选择,也就是AOF配置项appendfsync的三个可选值

  • Always:同步写回:每个写命令执⾏完,⽴⻢同步地将⽇志写回磁盘;
  • Everysec:每秒写回:每个写命令执⾏完,只是先把⽇志写到AOF⽂件的内存缓冲区,每隔⼀秒把缓冲 区中的内容写⼊磁盘;
  • No:操作系统控制的写回:每个写命令执⾏完,只是先把⽇志写到AOF⽂件的内存缓冲区,由操作系统 决定何时将缓冲区内容写回磁盘。
image-20210827134953513

AOF文件过大导致性能问题

AOF文件“性能问题”,主要在于以下三个⽅⾯:

  1. ⽂件系统本⾝对⽂件⼤⼩有限制,⽆法保存过⼤的⽂ 件;
  2. 如果⽂件太⼤,之后再往⾥⾯追加命令记录的话,效率也会变低;
  3. 如果发⽣宕机,AOF中 记录的命令要⼀个个被重新执⾏,⽤于故障恢复,如果⽇志⽂件太⼤,整个恢复过程就会⾮常缓慢,这就会 影响到Redis的正常使⽤。

AOF文件日志太大了怎么办

AOF重写机制就是在重写时,Redis根据数据库的现状创建⼀个新的AOF⽂件,也就是说,读取数据库中的所有键值对,然后对每⼀个键值对⽤⼀条命令记录它的写⼊

虽然AOF重写后,⽇志⽂件会缩⼩,但是,要把整个数据库的最新数据的操作⽇志都写回磁盘,仍然 是⼀个⾮常耗时的过程。这时,我们就要继续关注另⼀个问题了:重写会不会阻塞主线程?

AOF重写会阻塞主线程吗?

和AOF⽇志由主线程写回不同,重写过程是由后台线程bgrewriteaof来完成的,这也是为了避免阻塞主线 程,导致数据库性能下降。把重写的过程总结为“⼀个拷⻉,两处⽇志

⼀个拷⻉”就是指,每次执⾏重写时,主线程fork出后台的bgrewriteaof⼦进程。此时,fork会把主线程 的内存拷⻉⼀份给bgrewriteaof⼦进程,这⾥⾯就包含了数据库的最新数据。然后,bgrewriteaof⼦进程就可以在不影响主线程的情况下,逐⼀把拷⻉的数据写成操作,记⼊重写⽇志。
两处⽇志”⼜是什么呢?因为主线程未阻塞,仍然可以处理新来的操作。此时,如果有写操作,第⼀处⽇志就是指正在使⽤的AOF⽇志,Redis会把这个操作写到它的缓冲区。这样⼀来,即使宕机了,这个AOF⽇志的操作仍然是⻬全的,可以⽤于恢复。 ⽽第⼆处⽇志,就是指新的AOF重写⽇志。这个操作也会被写到重写⽇志的缓冲区。这样,重写⽇志也不会丢失最新的操作。等到拷⻉数据的所有操作记录重写完成后,重写⽇志记录的这些最新操作也会写⼊新的 AOF⽂件,以保证数据库最新状态的记录。此时,我们就可以⽤新的AOF⽂件替代旧⽂件了。

image-20210827142154245

每次AOF重写时,Redis会先执⾏⼀个内存拷⻉,⽤于重写;然后使⽤两个⽇志保证在重写过程中,新写⼊的数据不会丢失。⽽且因为Redis采⽤额外的线程进⾏数据重写,所以,这个过程并不会阻塞主线程。

问题:

  1. AOF⽇志重写的时候,是由bgrewriteaof⼦进程来完成的,不⽤主线程参与,我们今天说的⾮阻塞也是指 ⼦进程的执⾏不阻塞主线程。但是,你觉得,这个重写过程有没有其他潜在的阻塞⻛险呢?如果有的 话,会在哪⾥阻塞?
    1. AOF重写也有⼀个重写⽇志,为什么它不共享使⽤AOF本⾝的⽇志呢?

问题1回答:如果⼦进程写⼊事件过⻓,并且这段事件,会导致AOF重写⽇志,积累过多,当新的AOF⽂件完成后,还是需要写⼊⼤量AOF重写⽇志⾥的内容,可能会导致阻塞。

问题2回答:⽗⼦两个进程本来就没有需要竞争的数据,⽼师所指的两个⽇志应该是“AOF缓冲区”和"AOF重写缓冲区",⽽不是磁盘上的AOF⽂件,之所有另外有⼀个"AOF重写缓冲区",是因为重写期间,主进程AOF还在继续⼯作,还是会同步到旧的AOF⽂件中,同步成功后,“AOF缓冲区”会被清除,会被清除,会被清除!

RDB-内存快照

Redis提供了两个命令来⽣成RDB⽂件,分别是save和bgsave。

  • save:在主线程中执⾏,会导致阻塞;
  • bgsave:创建⼀个⼦进程,专⻔⽤于写⼊RDB⽂件,避免了主线程的阻塞,这也是Redis RDB⽂件⽣成的 默认配置。

为了快照⽽暂停写操作,肯定是不能接受的,Redis会借助操作系统提供的写时复制技术 (Copy-On-Write, COW),在执⾏快照的同时,正常处理写操作。 简单来说,bgsave⼦进程是由主线程fork⽣成的,可以共享主线程的所有内存数据。bgsave⼦进程运⾏后,开始读取主线程的内存数据,并把它们写⼊RDB⽂件。