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只记录操作命令的简单优势,颇有点“⻥和 熊掌可以兼得”的感觉。
总结
标签:快照,Redis,----,修改,内存,RDB,数据 From: https://www.cnblogs.com/xuzhidong/p/16833732.html
- 数据不能丢失时,内存快照和AOF的混合使⽤是⼀个很好的选择;
- 如果允许分钟级别的数据丢失,可以只使⽤RDB;
- 如果只⽤AOF,优先使⽤everysec的配置选项,因为它在可靠性和性能之间取了⼀个平衡