Redis持久化----RDB

Redis持久化----RDB

原理

当采用RDB这种方式来持久化Redis中的数据时,是向RDB文件中写入redis的快照;

什么是内存快照:

​ 所谓内存快照,就是指内存中的数据在某⼀个时刻的状态记录。这就类似于照⽚,当你给朋友拍照时,⼀张照⽚就能把朋友⼀瞬间的形象完全 记下来。

​ 对Redis来说,它实现类似照⽚记录效果的⽅式,就是把某⼀时刻的状态以⽂件的形式写到磁盘上,也就是快照。这样⼀来,即使宕机,快照⽂件也不会丢失,数据的可靠性也就得到了保证。这个快照⽂件就称为 RDB⽂件,其中,RDB就是Redis DataBase的缩写.

RDB的优点

在做内存恢复时数据比AOF快很多

原因:RDB记录的是某⼀时刻的数据,并不是操作,所以,在做数据恢复时,我们可以直接把RDB⽂ 件读⼊内存,很快地完成恢复。

RDB文件是给哪些数据做快照?

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

redis是如何生成RDB文件的

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

  • save:在主线程中执⾏,会导致阻塞;
  • bgsave:创建⼀个⼦进程,专⻔⽤于写⼊RDB⽂件,避免了主线程的阻塞,这也是Redis RDB⽂件⽣成的默认配置

快照时数据能修改吗?

​ 在给别⼈拍照时,⼀旦对⽅动了,那么这张照⽚就拍糊了,我们就需要重拍,所以我们当然希望对⽅保持不 动。对于内存快照⽽⾔,我们也不希望数据“动”。

举个例⼦。我们在时刻t给内存做快照,假设内存数据量是4GB,磁盘的写⼊带宽是0.2GB/s,简单来说,⾄少需要20s(4/0.2 = 20)才能做完。如果在时刻t+5s时,⼀个还没有被写⼊磁盘的内存数据A,被修改成了 A’,那么就会破坏快照的完整性,因为A’不是时刻t时的状态。因此,和拍照类似,我们在做快照时也不 希望数据“动”,也就是不能被修改。;

​ 但是,如果快照执⾏期间数据不能被修改,是会有潜在问题的。对于刚刚的例⼦来说,在做快照的20s时间 ⾥,如果这4GB的数据都不能被修改,Redis就不能处·理对这些数据的写操作,那⽆疑就会给业务服务造成巨⼤的影响

​ 你可能会想到,可以⽤bgsave避免阻塞啊。这⾥我就要说到⼀个常⻅的误区了,避免阻塞和正常处理写操作并不是⼀回事。此时,主线程的确没有阻塞,可以正常接收请求,但是,为了保证快照完整性,它只能处理读操作,因为不能修改正在执⾏快照的数据。

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

Redis中的COW

​ 简单来说,bgsave⼦进程是由主线程fork⽣成的,可以共享主线程的所有内存数据。bgsave⼦进程运⾏ 后,开始读取主线程的内存数据,并把它们写⼊RDB⽂件。

​ 此时,如果主线程对这些数据也都是读操作(例如图中的键值对A),那么,主线程和bgsave⼦进程相互不影响。但是,如果主线程要修改⼀块数据(例如图中的键值对C),那么,这块数据就会被复制⼀份,⽣成该数据的副本。然后,bgsave⼦进程会把这个副本数据写⼊RDB⽂件,⽽在这个过程中,主线程仍然可以 直接修改原来的数据。

​ 这既保证了快照的完整性,也允许主线程同时对数据进⾏修改,避免了对正常业务的影响。

​ 到这⾥,我们就解决了对“哪些数据做快照”以及“做快照时数据能否修改”这两⼤问题:Redis会使⽤ bgsave对当前内存中的所有数据做快照,这个操作是⼦进程在后台完成的,这就允许主线程同时可以修改数据。

多久做⼀次快照?

​ 快照的间隔时间变得很短,即使某⼀时刻发 ⽣宕机了,因为上⼀时刻快照刚执⾏,丢失的数据也不会太多。但是,这其中的快照间隔时间就很关键了。

如下图所⽰,我们先在T0时刻做了⼀次快照,然后⼜在T0+t时刻做了⼀次快照,在这期间,数据块5和9被修改了。如果在t这段时间内,机器宕机了,那么,只能按照T0时刻的快照进⾏恢复。此时,数据块5和9的修改值因为没有快照记录,就⽆法恢复了。

​ 所以,要想尽可能恢复数据,t值就要尽可能⼩,t越⼩,就越像“连拍”。那么,t值可以⼩到什么程度 呢,⽐如说是不是可以每秒做⼀次快照?毕竟,每次快照都是由bgsave⼦进程在后台执⾏,也不会阻塞主线程。

这种想法其实是错误的。虽然bgsave执⾏时不阻塞主线程,但是,如果频繁地执⾏全量快照,也会带来两 ⽅⾯的开销。

  • 一⽅⾯,频繁将全量数据写⼊磁盘,会给磁盘带来很⼤压⼒,多个快照竞争有限的磁盘带宽,前⼀个快照还 没有做完,后⼀个⼜开始做了,容易造成恶性循环。
  • 另⼀⽅⾯,bgsave⼦进程需要通过fork操作从主线程创建出来。虽然,⼦进程在创建后不会再阻塞主线程, 但是,fork这个创建过程本⾝会阻塞主线程,⽽且主线程的内存越⼤,阻塞时间越⻓。如果频繁fork出 bgsave⼦进程,这就会频繁阻塞主线程了。那么,有什么其他好⽅法吗?

​ 此时,我们可以做增量快照,所谓增量快照,就是指,做了⼀次全量快照后,后续的快照只对修改的数据进 ⾏快照记录,这样可以避免每次全量快照的开销。

在第⼀次做完全量快照后,T1和T2时刻如果再做快照,我们只需要将被修改的数据写⼊快照⽂件就⾏。但 是,这么做的前提是,我们需要记住哪些数据被修改了。你可不要⼩瞧这个“记住”功能,它需要我们使⽤ 额外的元数据信息去记录哪些数据被修改了,这会带来额外的空间开销问题。如下图所⽰:

如果我们对每⼀个键值对的修改,都做个记录,那么,如果有1万个被修改的键值对,我们就需要有1万条额 外的记录。⽽且,有的时候,键值对⾮常⼩,⽐如只有32字节,⽽记录它被修改的元数据信息,可能就需要 8字节,这样的画,为了“记住”修改,引⼊的额外空间开销⽐较⼤。这对于内存资源宝贵的Redis来说,有 些得不偿失。

到这⾥,你可以发现,虽然跟AOF相⽐,快照的恢复速度快,但是,快照的频率不好把握,如果频率太低, 两次快照间⼀旦宕机,就可能有⽐较多的数据丢失。如果频率太⾼,⼜会产⽣额外开销,那么,还有什么⽅ 法既能利⽤RDB的快速恢复,⼜能以较⼩的开销做到尽量少丢数据呢?

理论上的最优解--混合模式

Redis 4.0中提出了⼀个混合使⽤AOF⽇志和内存快照的⽅法。简单来说,内存快照以⼀定的频率执⾏,在两 次快照之间,使⽤AOF⽇志记录这期间的所有命令操作。

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

如下图所⽰,T1和T2时刻的修改,⽤AOF⽇志记录,等到第⼆次做全量快照时,就可以清空AOF⽇志,因为 此时的修改都已经记录到快照中了,恢复时就不再⽤⽇志了。

这个⽅法既能享受到RDB⽂件快速恢复的好处,⼜能享受到AOF只记录操作命令的简单优势,颇有点“⻥和 熊掌可以兼得”的感觉。

总结

  • 数据不能丢失时,内存快照和AOF的混合使⽤是⼀个很好的选择;
  • 如果允许分钟级别的数据丢失,可以只使⽤RDB;
  • 如果只⽤AOF,优先使⽤everysec的配置选项,因为它在可靠性和性能之间取了⼀个平衡

本文作者:鸽宗

本文链接:https://www.cnblogs.com/xuzhidong/p/16833732.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   鸽宗  阅读(63)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
  1. 1 水星记 REOL
水星记 - REOL
00:00 / 00:00
An audio error has occurred.

作词 : 郭顶

作曲 : 郭顶

编曲 : 郭顶

监制 : 郭顶

着迷于你眼睛

银河有迹可循

穿过时间的缝隙

它依然真实地

吸引我轨迹

这瞬眼的光景

最亲密的距离

沿着你皮肤纹理

走过曲折手臂

做个梦给你

做个梦给你

等到看你银色满际

等到分不清季节更替

才敢说沉溺

还要多远才能进入你的心

还要多久才能和你接近

咫尺远近却

无法靠近的那个人

也等着和你相遇

环游的行星

怎么可以

拥有你

这瞬眼的光景

最亲密的距离

沿着你皮肤纹理

走过曲折手臂

做个梦给你

做个梦给你

等到看你银色满际

等到分不清季节更替

才敢说沉溺

还要多远才能进入你的心

还要多久才能和你接近

咫尺远近却

无法靠近的那个人

也等着和你相遇

环游的行星

怎么可以

拥有你

还要多远才能进入你的心

还要多久才能和你接近

咫尺远近却无法靠近的那个人

要怎么探寻

要多么幸运

才敢让你发觉你并不孤寂

当我还可以再跟你飞行

环游是无趣

至少可以

陪着你