RDB
普通的八股不多说,说说使用bgsave后快照到底如何实现持久化并且还能继续提供服务。
bgsave会调用fork出一个子进程,那子进程要如何获取父进程的数据?
其实就是进程通信中的内存映射,将子进程的逻辑内存与父进程的逻辑内存映射到同一块物理内存。
但是如果父进程更改了数据怎么办?
在父进程修改的内存页(linux页4kb)内核才会将要更改的内存页实际拷贝到子进程里,他把拷贝延迟到实际需要拷贝的时候才真正进行拷贝。相对于没有COW时大大减少了内存的实际占用以及拷贝带来的性能消耗。
COW原理
fork()之后(fork()的实际开销就是复制父进程的页表以及给子进程创建一个进程描述符),kernel把父进程中所有的内存页的权限都设为read-only,然后子进程的地址空间指向父进程。当父子进程都只读内存时,相安无事。当其中某个进程写内存时,CPU硬件检测到内存页是read-only的,于是触发页异常中断(page-fault),陷入kernel的一个中断例程。中断例程中,kernel就会把触发的异常的页复制一份,于是父子进程各自持有独立的一份。
CopyOnWriteArrayList
在Java中也有类似的技术,不过是线程间的,线程安全的CopyOnWriteArrayList。底层通过复制数组的方式来实现,数据读取时直接读取,不需要锁,数据写入时,需要锁,且对副本进行操作,这样比直接对读写加锁避免了读的阻塞。同时为了保证可见性使用了volatile修饰数组。在完成数组复制修改操作后更新之前的数组。只有写写阻塞,通过ReentrentLock对数组大小变更加锁实现。
AOF
把每一个写请求记录日志,可以设置always、everysec、no
AOF重写
每条写都记录占用体积很大并且恢复时间也长,redis提供了日志重写功能,可以压缩命令。
创建一个新的 AOF 文件来代替原有的 AOF 文件, 新 AOF 文件和原有 AOF 文件保存的数据库状态完全一样, 但新 AOF 文件的体积小于等于原有 AOF 文件的体积。
生成期间将命令双写到原本AOF文件与AOF缓存文件中,可以保证原有AOF文件在写时命令也记录,生成的新AOF缓存文件命令也完整。
RDB+AOF
Redis4.0后使用混合模式,生成RDB后重新开始记录AOF,结合了RDB恢复快但备份久,AOF恢复慢但备份快的优点。
|