Redis:RDB 详解


Redis 已经有 AOF 了,为何还要有 RDB 呢?我们接下来就来看一看 RDB 与 AOF 的区别以及 RDB 的相关知识。

AOF方法的好处,是每次执行只需要记录操作命令,需要持久化的数据量不大。但是,也正因为记录的是操作命令,而不是实际的数据,所以,用AOF方法进行故障恢复的时候,需要逐一把操作日志都执行一遍。如果操作日志非常多,Redis 就会恢复得很缓慢,影响到正常使用。

**把某一时刻的状态以文件的形式写到磁盘上,也就是快照。**这样一来,即使宕机,快照文件也不会丢失,数据的可靠性也就得到了保证。这个快照文件称为 RDB 文件,RDB就是 Redis DataBase 的缩写。

和 AOF 相比,RDB 记录的是某一时刻的数据,并不是操作,所以,在做数据恢复时,可以直接把 RDB文件读入内存,很快地完成恢复。

给哪些内存数据做快照

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

给内存的全量数据做快照,把它们全部写入磁盘也会花费很多时间。而且,全量数据越多,RDB文件就越大,往磁盘上写数据的时间开销就越大。

Redis 是单线程的,要尽量避免所有会阻塞主线程的操作。

Redis提供了两个命令来生成 RDB文件,分别是save和 bgsave。

  • save:在主线程中执行,会导致阻塞;
  • bgsave:创建一个子进程,专门用于写入RDB文件,避免了主线程的阻塞,是RDB文件生成的默认配置

可以通过bgsave命令来执行全量快照,这既提供了数据的可靠性保证,也避免了对Redis的性能影响。

在对内存数据做快照时,这些数据还能被修改吗?如果数据能被修改,意味着Redis还能正常处理写操作。否则,所有写操作都得等到快照完了才能执行,性能一下子就降低了。

快照时数据能修改吗

避免阻塞和正常处理写操作并不是一回事。主线程的确没有阻塞,可以正常接收请求,但是,为了保证快照完整性,它只能处理读操作,因为不能修改正在执行快照的数据。

为了快照而暂停写操作,肯定是不能接受的。所以这个时候,Redis就会借助操作系统提供的写时复制技术(Copy-On-Write, cow),在执行快照的同时,正常处理写操作。

bgsave 子进程是由主线程 fork 生成的,可以共享主线程的所有内存数据。bgsave 子进程运行后,开始读取主线程的内存数据,并把它们写入 RDB 文件。

此时,如果主线程对这些数据也都是读操作,那么,主线程和 bgsave子进程相互不影响。但是,如果主线程要修改一块数据,那么,这块数据就会被复制一份,生成该数据的副本。然后,主线程在这个数据副本上进行修改。同时,bgsave子进程可以继续把原来的数据写入RDB文件。

可以每秒做一次快照吗

虽然每次快照都是由 bgsave 子进程在后台执行,也不会阻塞主线程。但是,如果频繁地执行全量快照,也会带来两方面的开销。

  • 一方面,频繁将全量数据写入磁盘,会给磁盘带来很大压力,多个快照竞争有限的磁盘带宽,前一个快照还没有做完,后一个又开始做了,容易造成恶性循环。

  • 另一方面,bgsave子进程需要通过fork操作从主线程创建出来。虽然,子进程在创建后不会再阻塞主线程,但是,fork这个创建过程本身会阻塞主线程,而且主线程的内存越大,阻塞时间越长,即fork操作的用时和 Redis 的数据量是正相关的,数据量越大,fork操作造成的主线程阻塞的时间越长。如果频繁fork 出 bgsave子进程,这就会频繁阻塞主线程了,所以,在 Redis中如果有一个bgsave在运行,就不会再启动第二个bgsave子进程

此时可以做增量快照,即做了一次全量快照后,后续的快照只对修改的数据进行快照记录,这样可以避免每次全量快照的开销。

这么做的前提是,需要记住哪些数据被修改了。这个“记住”功能**需要使用额外的元数据信息去记录哪些数据被修改了,这会带来额外的空间开销问题。**对于内存资源宝贵的Redis来说,有些得不偿失。

虽然跟AOF相比,快照的恢复速度快,但是,快照的频率不好把握,如果频率太低,两次快照间一旦宕机,就可能有比较多的数据丢失。如果频率太高,又会产生额外开销。

Redis 4.0中提出了一个混合使用AOF日志和内存快照的方法。即内存快照以一定的频率执行,在两次快照之间,使用AOF日志记录这期间的所有命令操作。

这样一来,快照不用很频繁地执行,这就避免了频繁fork对主线程的影响。而且,AOF日志也只用记录两次快照间的操作,也就是说,不需要记录所有操作了,因此,就不会出现文件过大的情况了,也可以避免重写开销。

这个方法既能享受到 RDB 文件快速恢复的好处,又能享受到 AOF 只记录操作命令的优势,建议使用。

写多读少的场景下,RDB存在的风险

如果有 100 个请求,80 个请求执行的是修改操作。用 RDB 做持久化有什么风险吗?

  • **内存不足的风险:**Redis fork 一个 bgsave 子进程进行 RDB 写入,如果主线程再接收到写操作,就会采用写时复制。写时复制需要给写操作的数据分配新的内存空间。此时,如果实例还有大量的新 key 写入或 key 修改,内存很快就会被吃光。如果主机开启了 Swap 机制,就会有一部分数据被换到磁盘上,当访问磁盘上的这部分数据时,性能会急剧下降。如果主机没有开启 Swap,会直接触发 OOM,整个 Redis 实例会面临被系统 kill 掉的风险。
  • **主线程和子进程竞争使用 CPU 的风险:**生成 RDB 的子进程需要 CPU 核运行,主线程本身也需要 CPU 核运行,如果 Redis 还启用了后台线程,此时,主线程、子进程和后台线程都会竞争 CPU 资源。在 CPU 核数量少时,就会影响到主线程处理请求的速度。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值