==作者:YB-Chi==
[toc]
什么是RDB
RDB(Redis DataBase)就是把某一时刻的状态以文件的形式写到磁盘上,也就是内存快照。
给哪些内存数据做快照?
Redis的数据都在内存中,为了提供所有数据的可靠性保证,它执行的是全量快照
RDB方式
对于Redis而言,它的单线程模型就决定了,我们要尽量避免所有会阻塞主线程的操作,所以,针对任何操作,我们都会提一个灵魂之问:“它会阻塞主线程吗?”RDB文件的生成是否会阻塞主线程,这就关系到是否会降低Redis的性能。
Redis提供了两个命令来生成RDB文件,分别是save和bgsave。
- save:在主线程中执行,会导致阻塞;
- bgsave:创建一个子进程,专门用于写入RDB文件,避免了主线程的阻塞,这也是Redis RDB文件生成的默认配置。
快照时数据能修改吗
简单来说,bgsave子进程是由主线程fork生成的,可以共享主线程的所有内存数据。bgsave子进程运行后,开始读取主线程的内存数据,并把它们写入RDB文件。
此时,如果主线程对这些数据也都是读操作(例如图中的键值对A),那么,主线程和bgsave子进程相互不影响。但是,如果主线程要修改一块数据(例如图中的键值对C),那么,这块数据就会被复制一份,生成该数据的副本。然后,bgsave子进程会把这个副本数据写入RDB文件,而在这个过程中,主线程仍然可以直接修改原来的数据。
这既保证了快照的完整性,也允许主线程同时对数据进行修改,避免了对正常业务的影响。
可以每秒做一次快照吗?
虽然bgsave执行时不阻塞主线程,但是,如果频繁地执行全量快照,也会带来两方面的开销。
一方面,频繁将全量数据写入磁盘,会给磁盘带来很大压力,多个快照竞争有限的磁盘带宽,前一个快照还没有做完,后一个又开始做了,容易造成恶性循环。
另一方面,bgsave子进程需要通过fork操作从主线程创建出来。虽然,子进程在创建后不会再阻塞主线程,但是,fork这个创建过程本身会阻塞主线程,而且主线程的内存越大,阻塞时间越长。如果频繁fork出bgsave子进程,这就会频繁阻塞主线程了。那么,有什么其他好方法吗?
如何平衡
Redis 4.0中提出了一个混合使用AOF日志和内存快照的方法。简单来说,内存快照以一定的频率执行,在两次快照之间,使用AOF日志记录这期间的所有命令操作。
如下图所示,T1和T2时刻的修改,用AOF日志记录,等到第二次做全量快照时,就可以清空AOF日志,因为此时的修改都已经记录到快照中了,恢复时就不再用日志了。
最后,关于AOF和RDB的选择问题,我想再给你提三点建议:
- 数据不能丢失时,内存快照和AOF的混合使用是一个很好的选择;
- 如果允许分钟级别的数据丢失,可以只使用RDB;
- 如果只用AOF,优先使用everysec的配置选项,因为它在可靠性和性能之间取了一个平衡。
摘选自:极客时间-Redis核心技术与实战