type
status
date
slug
summary
tags
category
icon
password
创建时间
Sep 12, 2024 07:30 AM
两个关键问题
- 对哪些数据做快照?──执行效率
- 做快照时,数据库还能正常操作吗?──Redis 是否阻塞
类比于:如何取景?也就是说,我们打算把哪些人、哪些物拍到照片中;在按快门前,要记着提醒朋友不要乱动,否则拍出来的照片就模糊了。
Redis 默认执行的是全量快照。
两个命令生成 RDB 文件:
save
和 bgsave
save
:在主线程中执行,会导致阻塞;
bgsave
:创建一个子线程,专门用于写入 RDB 文件,避免了主线程的阻塞,这也是 Redis RDB 文件生成的默认配置。
这里我就要说到一个常见的误区了,避免阻塞和正常处理写操作并不是一回事。此时,主线程的确没有阻塞,可以正常接收请求,但是,为了保证快照完整性,它只能处理读操作,因为不能修改正在执行快照的数据。──避免阻塞和正常处理写操作并不是一回事
为了快照而暂停写操作,肯定是不能接受的。这里使用写时复制技术(Copy On Write,COW)。
bgsave
子线程由主线程 fork 而来,可以共享主线程的所有内存数据。这里的操作和 AOF 很类似,也是在 fork 子线程的时候,可以共享主线成的所有内存数据。包括 Java 类库中,也有体现。在 String 类中,String 是不可变对象,改变值,会重新生成一个对象。

对于两个关键问题的回答:Redis 会默认使用
bgsave
对当前内存中的所有数据做快照,这个操作是子线程在后台完成的,这就允许主线程同时可以修改数据。如果频繁地执行全量快照,也会带来两方面的开销。
- 频繁将全量数据写入磁盘,会给磁盘带来很大压力,多个快照竞争有限的磁盘带宽,前一个快照还没有做完,后一个又开始做了,容易造成恶性循环。
bgsave
子进程需要通过 fork 操作从主线程创建出来。虽然,子进程在创建后不会再阻塞主线程,但是,fork
这个创建过程本身会阻塞主线程,而且主线程的内存越大,阻塞时间越长。如果频繁fork
出bgsave
子进程,这就会频繁阻塞主线程了。
混合使用 AOF 日志和 RDB 的方法
虽然跟 AOF 相比,快照的恢复速度快,但是,快照的频率不好把握,如果频率太低,两次快照间一旦宕机,就可能有比较多的数据丢失。如果频率太高,又会产生额外开销,那么,还有什么方法既能利用 RDB 的快速恢复,又能以较小的开销做到尽量少丢数据呢?
混合使用 AOF 日志和 RDB 的方法(Reids4.0):内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。
