AOF
把对redis的写操作记录下来,先执行命令,再执行写入,优势在于:
当然也有风险:丢失和对下一个命令造成阻塞
丢失的原因是执行写操作和记录日志是两个过程
下一个命令造成阻塞的原因是两个过程是同步的
第二个问题主要体现在,发生了将日志内容写入到硬盘,所以,有三种写回策略
先来看看Redis写入AOF日志的过程
写回策略就是作用于最后一步,有三种,Always、Everysec、No
三种都不能完美解决主进程阻塞和数据丢失的问题,三种各有利弊
三种写入策略的原理是控制fsync函数的调用时机
AOF重写机制
当该文件记录的很大之后,里面就会有一些对同一条的记录的多次操作,我们只需要保留最后一条最近的改动即可。
重写在日志文件大于64M的时候发生,不会放在主进程里面去做,放在后台子进程bgrewriteaof来完成,两个好处:不阻塞主进程(当发生页表复制和写时复制的时候,还是会阻塞);子进程带有父进程的数据副本
为什么需要子进程而不用子进程来做AOF的重写呢?
子线程之间共享内存,这样修改数据的时候需要通过加锁来保证数据的安全,影响性能。 如果是通过子线程来实现的话,父子进程会共享内存数据,但是这个共享的数据只能是以只读的方式来进行。当父子进程修改了任意一方日志文件,那这个时候就会发生写时复制,于是父子进程有了独立的数据副本。
子进程如何拥有父进程的数据副本呢?
fork子进程bgrewriteaof,操作系统会把主进程的页表复制一份给子进程,页表里面做的是虚拟内存和物理内存的映射,也就是说,子进程和父进程的虚拟内存空间不同,但是其对应的物理空间是同一个。
什么是写时复制?
当父子进程向这个内存发起写操作的时候,CPU会触发写保护中断,然后操作系统会在写保护中断函数里面进行物理内存的复制,更新页表,同时设置父子进程的读写权限是可读写,然后再会对这个内存进行读写。在发生写操作的时候,操作系统才会去复制物理内存。
主进程修改了已经存在的key-value的时候,就会发生写时复制,这里只会复制主进程修改的物理内存数据,没修改的物理内存还是与子进程是共享的。
RDB