引子
今天遇到一个面试题,若是机器内存是4G,redis已经占用了2G内存,这里redis执行RDB持久化,可否持久化成功? 上一秒还在说本身熟悉redis,下一秒就被光速打脸了,发现本身竟然没有深刻了解过redis的RDB持久化的机制。面试
1、Redis持久化的方式
redis持久化方式分为两种,分别是RDB和AOF。redis
- RDB(Redis DataBase):将某一时刻内存的数据以二进制的形式保存到磁盘中,RDB的数据完整性比不上AOF,可是对redis的QPS不会有太大的影响。
- AOF(Append Only File):将redis执行的命令按顺序不断追加到文件中,相似于MySQL的binlog日志。 其中,RDB持久化又涉及到两个操做命令,save和bgsave。
- save:通常是手动操做,会阻塞redis主进行执行。
- bgsave:经过配置文件来完成的RDB,执行的是bgsave命令,redis会fork一个子进程来执行持久化,只有在fork子进程的过程当中会短暂阻塞redis主进程,持久化的过程不会对主进行有影响。
2、fork和copyonwrite
Redis执行RDB持久化,主要依赖的是fork和copyonwrite技术。
fork函数是操做系统的API,用于从一个进程中建立一个子进程,这个子进程和父进程共享全部的内存信息、上下文、代码区、引用的资源等。可是,这样在子进程执行持久化的过程当中,主进程把内存中的数据修改了会怎么办呢?这里就会使用到copyonwrite技术。ide
- 当主进程fork一个子进程出来后,内核会把主进程全部的内存页都设置成read-only,此时,主进程和子进程都指向一样的内存地址。

- 当主进程须要对内存进行修改时,发现须要修改的内存页是read-only状态,此时会触发一页异常中断(page-fault)。内核会把须要修改的数据页复制一份,把主进程的地址指向新的复制数据页。

- 最后主进程再在新的内存数据页上进行修改操做。
3、总结
根据上面的技术,redis在执行RDB持久化的时候,持久化的内存数据就只会是fork子进程那一刻的内存数据,后续新的请求对持久化不会有影响。回到上面的面试题,redis是能够执行持久化成功的。函数
4、其它问题
- RDB的过程当中,每次更新数据都须要复制一份原有的数据,对redis的性能是否会有影响? 由于redis的使用场景大部分是读多写少的场景,所以更新数据时须要先对原数据复制对redis带来的性能影响是能够接受的。