一、RDB的实现
redis中数据持久化有两种方式,RDB快照(也是日志文件)和AOF日志。
- AOF 文件的内容是操作命令;
- RDB 文件的内容是二进制数据。
RDB 快照就是记录某一个瞬间的内存数据,记录的是实际数据,而 AOF 文件记录的是命令操作的日志,而不是实际的数据。redis中并没有专门用于载入RDB文件的命令,只要Redis服务器在启动时检测到RDB文件存在,它就会自动载入RDB文件。
1.实现原理
Redis 提供了两个命令来生成 RDB 文件,分别是 save
和 bgsave
命令。
- save:执行了 save 命令,就会在主线程生成 RDB 文件,由于和执行操作命令在同一个线程,所以如果写入 RDB 文件的时间太长,会阻塞主线程。
- bgsave:执行了 bgsava 命令,会创建一个子进程来生成 RDB 文件,这样可以避免主线程的阻塞。
Redis 还可以通过配置文件的选项来实现每隔一段时间自动执行一次 bgsava 命令,默认配置如下:
save 900 1
save 300 10
save 60 10000
- 900 秒之内,对数据库进行了至少 1 次修改;
- 300 秒之内,对数据库进行了至少 10 次修改;
- 60 秒之内,对数据库进行了至少 10000 次修改。
只要条件满足其中任意一个,就会执行bgsave。
这就是 RDB 快照的缺点,在服务器发生故障时,丢失的数据会比 AOF 持久化的方式更多,因为 RDB 快照是**全量快照(保存内存中所有数据)**的方式,因此执行的频率不能太频繁,否则会影响 Redis 性能,而 AOF 日志可以以秒级的方式记录操作命令,所以丢失的数据就相对更少
2.数据修改问题
由于是子进程创建RDB文件,所以主进程是可以继续工作的。如果主线程(父进程)要修改共享数据里的某一块数据(比如键值对 A
)时,就会发生写时复制,于是这块数据的物理内存就会被复制一份(键值对 A'
),然后主线程在这个数据副本(键值对 A'
)进行修改操作。与此同时,bgsave 子进程可以继续把原来的数据(键值对 A
)写入到 RDB 文件。
所以如果进行数据修改的话,RDB文件中存的是修改之前的数据,而最新数据只能留给下一次bgsave快照。
二、RDB和AOF混合使用
尽管 RDB 比 AOF 的数据恢复速度快,但是快照的频率不好把握:
- 如果频率太低,两次快照间一旦服务器发生宕机,就可能会比较多的数据丢失;
- 如果频率太高,频繁写入磁盘和创建子进程会带来额外的性能开销。
那有没有什么方法不仅有 RDB 恢复速度快的优点,又有 AOF 丢失数据少的优点呢?
在 Redis 4.0 中提出了混合使用 AOF 日志和RDB内存快照,也叫混合持久化。
//设置为yes开启混合持久化
aof-use-rdb-preamble yes
1.实现原理
当开启了混合持久化时,在 AOF 重写日志时,fork
出来的重写子进程会先将与主线程共享的内存数据以 RDB 方式写入到 AOF 文件,然后主线程处理的操作命令会被记录在重写缓冲区里,重写缓冲区里的增量命令会以 AOF 方式写入到 AOF 文件,写入完成后通知主进程将新的含有 RDB 格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件。
混合持久化中,AOF 文件的前半部分是 RDB 格式的全量数据,后半部分是 AOF 格式的增量数据。
加载完 RDB 的内容后,才会加载后半部分的 AOF 内容,这里的内容是 Redis 后台子进程重写 AOF 期间,主线程处理的操作命令,可以使得数据更少的丢失。
参考
【小林coding】