11、Redis的持久化(RDB、AOF)
写在前面的话:读书破万卷,编码如有神
----------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------
1、Redis持久化概述
Redis持久化分成两种方式:RDB(redis database)、 AOF(append only file)
- RDB是在不同的时间点,将Redis某一时刻的数据生成快照并存储到磁盘上。
- AOF是只允许追加不允许改写的文件,是将Redis执行过的所有写指令记录下来,在下次redis重启的时候,只要把这些写指令从前到后重复执行一遍,就可以实现数据恢复。
- RDB和AOF两种方式可以同时使用,在这种情况下,如果Redis重启的话,则会优先采用AOF方式进行数据恢复,这是因为AOF方式的数据恢复完整度更高
- 可以关闭RDB和AOF,这样的话,Redis就变成了一个纯内存数据库,就像Memcached一样
- 通过配置redis.config中的appendonly为yes就可以打开AOF功能
----------------------------------------------------------------------------------------
2、RDB
RDB方式,Redis会单独创建(fork)一个子进程进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能。
如果需要进行大规模数据的恢复,且对数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加高效。RDB的缺点是最后一次持久化后的数据可能丢失。
2.1、RDB的问题
- fork一个进程时,内存的数据也被复制了,即内存会是原来的两倍
- 每次快照持久化都是将内存数据完整写入到磁盘一次,并不是增量的只同步脏数据。如果数据量大的话,而且写操作比较多,必然会引起大量的磁盘io操作,可能会严重影响性能
- 由于快照方式是在一定间隔时间做一次,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改。
2.2、触发快照的情况
- 根据配置规则进行自动快照
- 用户执行save或bgsave命令
- 执行flushall命令
- 执行复制replication时
2.3、RDB相关命令:
- save命令:(生产环境不要用)执行save命令时,redis会阻塞所有客户端的请求,然后同步进行快照操作。
- bgsave命令:执行bgsave命令时,redis会在后台异步进行快照操作,快照同时还可以响应客户端请求。可以通过lastsave命令获取最后一次成功执行快照的时间。
- flushall命令:这个命令会导致redis清除内存中的所有数据,如果定义了自动快照的条件,那么无论是否满足条件,都会进行一次快照操作;如果没有定义自动快照的条件,那么不会进行快照。
2.4、快照部分的配置信息
配置信息如下:
1 ################################ SNAPSHOTTING ################################ 2 # 3 # Save the DB on disk: 4 # 5 # save <seconds> <changes> 6 # 7 # Will save the DB if both the given number of seconds and the given 8 # number of write operations against the DB occurred. 9 # 10 # In the example below the behaviour will be to save: 11 # after 900 sec (15 min) if at least 1 key changed 12 # after 300 sec (5 min) if at least 10 keys changed 13 # after 60 sec if at least 10000 keys changed 14 # 15 # Note: you can disable saving completely by commenting out all "save" lines. 16 # 17 # It is also possible to remove all the previously configured save 18 # points by adding a save directive with a single empty string argument 19 # like in the following example: 20 # 21 # save "" 22 23 save 900 1 24 save 300 10 25 save 60 10000 26 27 # By default Redis will stop accepting writes if RDB snapshots are enabled 28 # (at least one save point) and the latest background save failed. 29 # This will make the user aware (in a hard way) that data is not persisting 30 # on disk properly, otherwise chances are that no one will notice and some 31 # disaster will happen. 32 # 33 # If the background saving process will start working again Redis will 34 # automatically allow writes again. 35 # 36 # However if you have setup your proper monitoring of the Redis server 37 # and persistence, you may want to disable this feature so that Redis will 38 # continue to work as usual even if there are problems with disk, 39 # permissions, and so forth. 40 stop-writes-on-bgsave-error yes 41 42 # Compress string objects using LZF when dump .rdb databases? 43 # For default that's set to 'yes' as it's almost always a win. 44 # If you want to save some CPU in the saving child set it to 'no' but 45 # the dataset will likely be bigger if you have compressible values or keys. 46 rdbcompression yes 47 48 # Since version 5 of RDB a CRC64 checksum is placed at the end of the file. 49 # This makes the format more resistant to corruption but there is a performance 50 # hit to pay (around 10%) when saving and loading RDB files, so you can disable it 51 # for maximum performances. 52 # 53 # RDB files created with checksum disabled have a checksum of zero that will 54 # tell the loading code to skip the check. 55 rdbchecksum yes 56 57 # The filename where to dump the DB 58 dbfilename dump_6379.rdb 59 60 # The working directory. 61 # 62 # The DB will be written inside this directory, with the filename specified 63 # above using the 'dbfilename' configuration directive. 64 # 65 # The Append Only File will also be created inside this directory. 66 # 67 # Note that you must specify a directory here, not a file name. 68 dir ./
(1)save * * : 保存快照的频率,第一个*表示多长时间,单位是秒;第二个*表示至少执行写操作的次数;在一定时间内至少执行一定数量的写操作时,就自动保存快照,可设置多个条件。
- 如果想要禁用RDB持久化的策略,只要不设置任何save指令,或者给save传入一个空字符串参数就可以。
- 如果用户开启了RDB快照功能,那么在redis持久化数据到磁盘时如果出现失败,默认情况下,redis会停止接受所有的写请求,这样做的好处在于可以让用户很明显的知道内存的数据和磁盘上的数据已经不存在一致性了。如果一下次RDB持久化成功,redis会自动恢复写请求。
(2)stop-writes-on-bgsave-error : 如果配置成no,表示不在乎数据不一致或者其他的手段发现和控制这种不一致,那么在快照写入失败时,也就能确保redis继续接受新的写请求。
(3)rdbcompression :对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能。
(3)rdbchecksum : 在存储快照后,还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大性能提升,可以关闭此功能。
(4)dbfilename : 数据快照文件名(只是文件名,不包括目录),默认dump.rdb
(5)dir : 数据快照的保存目录,默认是当前路径
----------------------------------------------------------------------------------------
3、AOF
默认的AOF持久化策略是每秒钟fsync一次,fsync是指把缓存中的写指令记录到磁盘中,在这种情况下,Redis仍可以保持很高的性能。
当然由于OS会在内核中缓存write做的修改,所以可能不是立即写到磁盘上。这样AOF方式的持久化也还是有可能会丢失部分修改。不过可以通过配置文件告诉redis,想要通过fsync函数强制os写入到磁盘的时机。
AOF方式在同等数据规模的情况下,AOF文件要比RDB文件的体积大,因此AOF方式的恢复速度也要慢于RDF方式
3.1、AOF日志恢复
如果在追加日志时,恰好遇到磁盘空间满或者断电的情况,导致日志写入不完整,也没有关系,redis提供了redis-check-aof工具,可以用来进行日志修复,基本步骤如下:
- 备份被写坏的AOF文件
- 运行redis-check-aof -fix 进行修复
- 用diff -u来看下两个文件的差异,确认问题点
- 重启redis,加载修复后的AOF文件
3.2、AOF重写
AOF采用文件追加方式,这会导致AOF文件越来越大,为此,Redis提供了AOF文件重写(rewrite)机制,即当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。可以使用命令:bgrewriteaof
3.3、AOF重写触发机制
Redis是这样工作的:Redis会记录上次重写时AOF大小,假如自启动至今还没有进行过重写,那么启动时AOF文件的大小会被作为基准值,这个基准值会和当前的AOF大小进行比较,如果当前AOF大小超出所设置的增长比例,则会触发重写。另外,你还需要设置一个最小大小,是为了防止在AOF很小时就触发重写。
3.4、AOF重写的基本原理
- 在重写开始前,redis会创建一个"重写子进程",这个子进程会读取现有的AOF文件,并将其包含的指令进行分析解压缩并写入到一个临时文件中
- 与此同时,主进程将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的AOF文件中,这样做是保证原有的AOF文件的可用性,避免在重写过程中出现意外
- 当"重写子进程"完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新AOF文件中
- 当追加结束后,redis就会用新AOF文件来替代旧AOF文件,之后再有新的写指令,就都会追加到新的AOF文件中
- 重写AOF文件的操作,并没有读取旧的AOF文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的AOF文件,这点和快照有点类似。
3.5、AOF配置信息
(1)appendonly : 是否开启AOF
(2)appendfilename : 设置AOF的日志文件名
(3)appendfsync : 设置AOF日志如何同步到磁盘,fsync()调用,用来告诉操作系统立即将缓存的指令写入磁盘,有三个选项:
- always : 每次写都强制调用fsync,这种模式下,redis会相对较慢,但数据最安全
- everysec : 每秒启用一次fsync。(推荐)
- no : 不调用fsync()。而是让操作系统自行决定sync的时间。这种模式下,redis的性能会最快
(4)no-appendfsync-on-write : 设置当redis在rewrite的时候,是否允许appendsync。因为redis进程在进行AOF重写的时候,fsync()在主进程中的调用会被阻止,也就是redis的持久化功能暂时失效,默认为no,这样能保证数据安全
(5)auto-aof-rewrite-min-size : 设置一个最小大小,是为了防止在aof很小时就触发重写
(6)auto-aof-rewrite-percentage : 设置自动进行aof重写的基准值,也就是重写启动时的AOF文件大小,假如redis自启动至今还没有进行过重写,那么启动时aof文件的大小会被作为基准值,这个基准值会和当前的aof大小进行比较。如果当前aof大小超出设置的增长比例,则会触发重写,如果设置auto-aof-rewrite-percentage为0,则会关闭此重写功能。