《Redis 核心技术与实战》学习笔记 Day three

134 阅读5分钟

1.RDB的做了什么动作?

Redis 的数据都在内存中,为了提供所有数据的可靠性保证,它执行的是全量快照,也就是说,把内存中的所有数据都记录到磁盘中

2.两个生成RDB文件的命令

  • save:在主线程中执行,会导致阻塞;
  • bgsave:创建一个子进程,专门用于写入 RDB 文件,避免了主线程的阻塞,这也是Redis RDB 文件生成的默认配置。 所以可以通过 bgsave 命令来执行全量快照,这既提供了数据的可靠性保证,也避免了对 Redis 的性能影响。

3.快照时数据能修改吗?

这个问题非常重要,这是因为,如果数据能被修改,那就意味着 Redis 在执行快照的同时,有写数据的请求来的时候,还能正常处理写操作请求。否则,所有写操作都得等到快照完了才能执行,性能一下子就降低了。

  • 举个例子,我们在时刻 t 给内存做快照,假设内存数据量是 4GB,磁盘的写入带宽是 0.2GB/s,简单来说,至少需要 20s(4/0.2 = 20)才能做完。如果在时刻 t+5s 时,一个还没有被写入磁盘的内存数据 A,被修改成了 A’,那么就会破坏快照的完整性,因为 A’不是时刻 t 时的状态。因此,和拍照类似,我们在做快照时也不希望数据“动”,也就是不能被修改。如果快照执行期间数据不能被修改,是会有潜在问题的。对于刚刚的例子来说,在做快照的 20s 时间里,如果这 4GB 的数据都不能被修改,Redis 就不能处理对这些数据的写操作,那无疑就会给业务服务造成巨大的影响。
  • 所以,此时Redis就会借助操作系统提供的写时复制技术(Copy-On-Write, COW),在执行快照的同时,主线程能够正常处理写操作。

4.写时复制技术具体过程是怎么样的?

  • 简单来说,bgsave 子进程是由主线程 fork 生成的,可以共享主线程的所有内存数据。bgsave 子进程运行后,开始读取主线程的内存数据,并把它们写入 RDB 文件。如果主线程对这些数据也都是读操作(例如图中的键值对 A),那么,主线程和 bgsave 子进程相互不影响。
  • 如果是主线程有写数据请求,具体过程:主线程要修改一块数据(例如图中的键值对 C),那么,这块数据就会被复制一份,生成该数据的副本(键值对 C’)。然后,主线程在这个数据副本上进行修改。同时,bgsave 子进程可以继续把原来的数据(键值对 C)写入 RDB 文件。如下图所示: 这既保证了快照的完整性,也允许主线程同时对数据进行修改,避免了对正常业务的影响

5.快照能做连拍吗?这样做又有什么缺点呢?

频繁拍照,即连拍,我们在概念说了,RDB是把数据存入磁盘里面,虽然 bgsave 执行时不阻塞主线程,但是,如果频繁地执行全量快照,也会带来两方面的开销。

  • 一方面,频繁将全量数据写入磁盘,会给磁盘带来很大压力,多个快照竞争有限的磁盘带宽,前一个快照还没有做完,后一个又开始做了,容易造成恶性循环。
  • 另一方面,bgsave 子进程需要通过 fork 操作从主线程创建出来。虽然,子进程在创建后不会再阻塞主线程,但是,fork 这个创建过程本身会阻塞主线程,而且主线程的内存越大,阻塞时间越长。如果频繁 fork 出 bgsave 子进程,这就会频繁阻塞主线程了(所以,在 Redis 中如果有一个 bgsave 在运行,就不会再启动第二个 bgsave 子进程)。
  • 解决办法:此时,我们可以做增量快照,所谓增量快照,就是指,做了一次全量快照后,后续的快照只对修改的数据进行快照记录,这样可以避免每次全量快照的开销。但是,增量快照也需要我们使用额外的元数据信息去记录哪些数据被修改了,这会带来额外的空间开销问题。如下图所示:

image.png 如果有 1 万个被修改的键值对,我们就需要有 1 万条额外的记录。而且,有的时候,键值对非常小,比如只有 32 字节,而记录它被修改的元数据信息,可能就需要 8 字节,这样的画,为了“记住”修改,引入的额外空间开销比较大。这对于内存资源宝贵的 Redis 来说,有些得不偿失。

  • 虽然跟 AOF 相比,快照的恢复速度快,但是,快照的频率不好把握,如果频率太低,两次快照间一旦宕机,就可能有比较多的数据丢失。如果频率太高,又会产生额外开销,那么,还有什么方法既能利用 RDB 的快速恢复,又能以较小的开销做到尽量少丢数据呢?

6.AOF和RDB混合使用

Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。简单来说,内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。这样一来,快照不用很频繁地执行,这就避免了频繁 fork 对主线程的影响。而且,AOF 日志也只用记录两次快照间的操作,也就是说,不需要记录所有操作了,因此,就不会出现文件过大的情况了,也可以避免重写开销。