关于Redis两种持久化方式的说明
在说Redis持久化之前,需要搞明白什么是数据库状态这个概念,因为持久化的就是将内存中的数据库状态保存到磁盘上。那么什么是数据库状态呢?Redis是一个key-value数据库服务器,一般默认是有16个数据库,可以使用select <index>命令进行切换(0-15),这每个非空的数据库又可以包含任意多个键值对,为了方便起见,我们将数据库服务器中的非空数据库以及它们的键值对通常为【数据库状态】,所以这里持久化,说的不是一个数据库,而是服务器上的所有非空数据库。
接着,我们继续来说redis的两种持久化方式,一种是RDB持久化,一种是AOF持久化,这两种持久化方式都可以将内存中的数据库状态保存到磁盘上,但是原理非常不同,我们逐一来看看,首先说一下RDB持久化。
RDB持久化默认生成的文件名为dump.rdb,这个可以通过配置文件配置,RDB文件一个经过压缩的二进制文件,接下来介绍一些rdb文件结构,RDB文件包含五个部分,分别是【Redis | db_version | databases | EOF | check_sum】开头的Redis表示这是一个RDB文件,服务器可以通过这个快速检查载入的文件是否是rdb文件,db_version是一个整数,代表RDB文件的版本,databases部分包含0个或者是任意多个数据库,以及数据库中的键值对数据,如果数据库状态是空,那么这部分也是空的,这部分的结构如下【SELECTDB | db_number | key_values_pairs】其中SELECTDB是一个常量,长度是一字节,当服务器遇到这个的时候,知道接下来要读入的将是一个数据库号码,db_number中保存的是一个数据库号码(0-15)这两部分结合就可以切换到相应的数据库,然后读取键值对了,键值对的部分的结构有两种,一种是带过期值的,一种是不带过期值的,如果是带过期值,那么结构是【EXPIRETIME_MS | ms | TYPE | key | value】第一个常量和SELECTDB一样,第二部分是毫秒为单位的UNIX时间戳,就是键值对的过期时间,然后是TYPE记录了value的类型,是String,list,set,zset,hash,等。不带过期值的键值对部分的结构没有前两部分,只是【TYPE | key | value】
RDB持久化可以通过命令进行手动执行,也可以配置好后让服务器自动执行,手动执行可以使用Redis命令【SAVE】或者【BGSAVE】,这两个命令有一些差别,需要说明一下,save命令会阻塞服务器进程,也就说,但save命令执行的时候服务器不能够处理任何命令请求,知道save命令执行完毕,RDB文件创建完毕,bgsave命令不会阻塞服务器,而是通过派生出一个子进程,然后由子进程负责创建RDB文件,服务器进程继续处理命令请求,这里需要说明一下,bgsave处理期间,服务器进程虽然能够继续处理命令请求,但是save,bgsave,bgrewriteaof这三个命令的处理方式会和平时有所不同,在bgsave期间,save命令会被服务器拒绝,服务器禁止save和bgsave同时执行,避免父进程和子进程同时执行两个rdbSave(创建RDB文件的实际工作实际上是由rdbSave函数完成,save和bgsave都会调用这个函数,只是调用的方式不同)调用,bgsave命令在bgsave期间也会被拒绝,理由和拒绝save的理由一样,两个bgsave也会产生竞争,bgrewriteaof命令会被延迟到bgsave执行完毕之后执行。
Redis没有专门的RDB文件载入命令,只要Redis服务器开启,就会检测RDB文件是否存在,就会自动载入RDB文件,这里需要说明一点,如果服务器开启了AOF持久化功能,服务器会优先使用AOF文件来还原数据库状态,只有在AOF持久化功能关闭的时候,才会使用RDB文件来还原数据库状态。
接下来说一下,RDB自动保存,前面已经说了,RDB可以通过手动执行,SAVE命令和BGSAVE命令,也可以通过配置让服务器自动执行,那么如何配置呢?
Redis.conf中可以配置,默认配置如下:
save 900 1
save 300 10
save 60 10000
以上表示的意思是,
- 900秒之内对服务进行了至少一次修改
- 300秒之内服务器进行了至少10次修改
- 60秒之内对服务器进行了至少10000次修改。
这些条件满足其中的任意一个bgsave命令就会自动执行。
那么你可能会好奇,服务器是怎么知道我做了多少修改的?服务器中有个dirty计数器和一个lastsave时间戳
当服务器执行一个数据库修改命令之后,dirty计数器就会进行更新,命令修改了多少次数据库,dirty就会增加多少,如:【set msg hello】修改了一个,那么dirty就加一,如果【mset msg word name nihao age 20】那么dirty就增加三
lastsave属性记录上次服务器执行保存操作的时间,是一个unix时间戳,通过这两个属性,可以很简单的距离上次保存已经多少时间了,以及修改了多少次数据库,一旦满足以上三个条件,那么就自动调用bgsave命令,同时更新lastsave属性和dirty属性归零。
至于检查保存条件是否满足这个工作,是由Redis服务器周期性操作函数serverCron默认间隔100毫秒执行一次检查,这个函数有很多地方用到,注意一下,这个函数是对正在运行的服务器进行维护的函数,在Redis事件中会有提到(Redis服务器是一个事件驱动程序,什么是事件驱动呢?就是发生事件的时候才会动一下,不然就跟死了一样,事件驱动又分为文件事件和时间事件,ServerCron就是一种时间驱动,至于文件驱动,其实就是客户端发过来一个命令,服务器才会去执行,然后给客户端返回结果)
最后说一点,Redis本身自带了一个RDB文件检查工具redis-check-dump,可以使用这个工具对rdb文件是否完整进行检查。
Redis 的详细介绍:请点这里
Redis 的下载地址:请点这里