场景题—— Redis 进行RDB 持久化且内存有限时潜在风险

54 阅读3分钟

写在开头:

最近正在秋招后端面试,将来打算进入此行业进行发展,简单记录,见解不足之处,前辈们海涵,不吝赐教~

问题

面试官问:如果你有一台16G物理内存的服务器,Redis当中存储了8G的数据,此时如果进行RDB,请问可能会出现什么情况?

回答思路

  1. 说明 RBD 的实现方式:RDB 有两种方式,savebgsave,一般来说,我们都是使用的后者,可以尽可能避免主进程的阻塞。其过程是主进程调用fork()函数,创建一个子进程,子进程实现 RDB 持久化。
  2. 表明创建子进程的时候发生了什么:因为我们要进行数据的快照,所以我们需要子进程拥有和父进程一样的数据,才可以创建快照,由于虚拟内存的存在,可以让我们的这个过程变得较为简单,使用 COW(CopyOnWrite),只复制虚拟内存页表,那么两个进程就可以同时访问同一块物理内存,并且复制行为只需要复制虚拟页表即可,主线程阻塞时间较短。
  3. COW 的问题:写时复制,顾名思义,当出现写的时候,发生真正的复制行为。如果在 RDB 未完成的时候发生了修改行为,就会触发中断,进行物理内存的复制,此时主进程会阻塞很久,其次是物理空间不一定会够用,如果内存溢出,则会根据内存淘汰策略,发生swap,此时就会发生磁盘 IO。

我的回答

RDB 的过程中,有可能会发生两次阻塞。第一次来自于调用 fork 函数的时候,操作系统执行 COW,需要复制父进程的虚拟页表,此时会卡顿一次。其次,由于物理内存只有 16G,当 Redis 当中的原有数据发生修改的时候,会触发中断,此时需要复制物理内存,会中断很久,并且,16G 内存不足以支撑 8G 的 Redis 的数据的物理内存的全量复制,会按照操作系统的内存淘汰机制触发 swap 机制,导致磁盘 IO,会让 Redis 的访问速度降低,整个过程中,还会导致 CPU 的占用飙升。若禁用了操作系统的 swap 机制,还有可能发生 OOM,导致 Redis 服务崩溃。

补充

当触发物理内存的复制时,仅针对于内存页被修改的物理内存,但是 Redis 的内存碎片化比较严重或者对大量的数据都进行了修改时,就会触发大批量的物理内存复制。可以通过 Redis 自带的内存碎片的整理机制或限流算法降低全量物理内存复制的可能。

反思:

  1. fork 创建的是线程还是进程?是进程,但是可能会表述成线程,需要避免。
  2. 并不是修改了数据就一定会发生全量的物理内存复制,而是仅对于修改了的数据,但是中断的频繁触发是可能的。
  3. Redis 的内存碎片化之前并没有太在意,此时看来,对 Redis 的内存的碎片化的处理也需进行学习和补充,因为内存的碎片化会导致 COW 后,物理内存的复制是否被频繁触发,可能还会影响 CPU cache 的命中率,无法充分发挥局部性原理,以及内存的利用率不高频繁 swap 等问题。