redis之AOF日志 1.0

AOF日志持久化的方式就是记录每次对于执行的命令,这些命令是以文本的形式保存的

aof记录每条命令的方式是先让数据库执行,如果执行成功则记录入aof日志文件当中

而aof日志也具有很大的风险,如果刚执行一条命令,还没有来得及写会磁盘,就宕机了,那么下一次就无法恢复数据库了,同时如果AOF 日志也是在主线程中执行的,如果在把日志文件写入磁盘时,磁盘写压力大,

就会导致写盘很慢,进而导致后续的操作也无法执行了。

下面介绍三种aof写会策略:
always:每执行一条命令就同步写回磁盘

everysec:每秒写会:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘

no:每个命令执行完,都是只将命令写入aof缓冲区,什么时候将缓冲区内容写会磁盘将由操作系统决定

“同步写回”可以做到基本不丢数据,但是它在每一个写命令后都有一个慢速的落盘操作,不可避免地会影响主线程性能;

虽然“操作系统控制的写回”在写完缓冲区后,就可以继续执行后续的命令,但是落盘的时机已经不在 Redis 手中了,只要 AOF 记录没有写回磁盘,一旦宕机对应的数据就丢失了;

“每秒写回”采用一秒写回一次的频率,避免了“同步写回”的性能开销,虽然减少了对系统性能的影响,但是如果发生宕机,上一秒内未落盘的命令操作仍然会丢失。所以,这只能算是,在避免影响主线程性能和避免数据丢失两者间取了个折中。

但是aof日志过大的话也会对与性能造成影响,如果aof文件太大,向其中增加命令时效率也会变低,如果宕机时,恢复数据库时需要一条条的执行命令,其中还包括冗余的命令,如果文件很大,那么执行命令的速度就会很慢,也会影响到redis的性能

这里就要引入到aof重写机制上去了

aof重写机制:redis根据数据库现状创建一个新的aof日志文件,读取数据库中的键值对,然后对每一个键值用一条命令记录它的写入,这些命令都会记录入新的aof文件

和 AOF 日志由主线程写回不同,重写过程是由后台线程 bgrewriteaof 来完成的,这也是为了避免阻塞主线程,导致数据库性能下降。

每次执行重写时,主线程fork出后台的bgrewriteaof子进程,此时fork会把父进程的页表复制给子进程,子进程复制了父进程的页表,这样就能共享访问父进程的数据了,这样就能把数据写成操作了

使用子进程时有一个问题,子进程在aof重写期间服务器还需要继续处理命令请求,而新的命令还会对现有的数据进行修改,从而使得服务器当前的数据库状态与重写后的aof文件所保存的状态不一致,为了解决这个问题,

redis创建了一个aof重写缓冲区,这个缓冲区一直存在,在服务器创建完子进程之后开始使用,当redis执行完一个写命令后,它会同时将写命令发送给aof缓冲区与aof重写缓冲区,当子进程完成aof重写工作后,会向父进程发送一个信号,父进程在接到

该信号后,会调用一个信号处理函数,将aof重写后缓冲区中的所有内容,写入到新的aof文件中,这时新的aof文件中所保存的数据库状态将和服务器当前的数据库状态一致,然后让新的aof文件覆盖现有的aof文件,完成新旧两个文件的替换。

特别提醒

因为主线程未阻塞,仍然可以处理新来的操作。此时,如果有写操作,对于正在使用的 AOF 日志,Redis 会把这个操作写到它的缓冲区。这样一来,即使宕机了(未能生成新的aof文件),

这个 AOF 日志的操作仍然是齐全的,可以用于恢复。对应上面所说的     “将写命令发送给aof缓冲区(这个缓冲区是指在没有重写时刷盘(将接受的命令写入磁盘,相当于执行write后的命令写入地方)的缓冲区,所有的写命令会追加到aof_buf(缓冲区)中(write),aof缓冲区会根据对应的策略向硬盘做同步操作(fsync 针对文件做强制硬盘同步))与aof重写缓冲区“

 

 

扩展:写实复制:写时复制的底层实现机制

对 Redis 来说,主线程 fork 出 bgsave 子进程后,bgsave 子进程实际是复制了主线程的页表。这些页表中,就保存了在执行 bgsave 命令时,主线程的所有数据块在内存中的物理地址。这样一来,bgsave 子进程生成 RDB 时,就可以根据页表读取这些数据,再写入磁盘中。如果此时,主线程接收到了新写或修改操作,那么,主线程会使用写时复制机制。具体来说,写时复制就是指,主线程在有写操作时,才会把这个新写或修改后的数据写入到一个新的物理地址中,并修改自己的页表映射。

 

举例子:bgsave 子进程复制主线程的页表以后,假如主线程需要修改虚页 7 里的数据,那么,主线程就需要新分配一个物理页(假设是物理页 53),然后把修改后的虚页 7 里的数据写到物理页 53 上,而虚页 7 里原来的数据仍然保存在物理页 33 上。这个时候,虚页 7 到物理页 33 的映射关系,仍然保留在 bgsave 子进程中。所以,bgsave 子进程可以无误地把虚页 7 的原始数据写入 RDB 文件。这里很好的解释了对于rdb快照如果在恢复时出现写入修改命令的应对策略。

 

posted @ 2020-10-13 20:31  xzwcomeon  阅读(446)  评论(0编辑  收藏  举报