首页 > 代码库 > 细说Redis持久化机制

细说Redis持久化机制

概述

Redis不仅可以作为缓存来使用,也可以作为内存数据库。Redis作为内存数据库使用时,必须要解决一个问题:数据的持久性。有些将Redis作为缓存使用的场景也需要将缓存的数据持久化到存储介质上,这样在Redis重启后仍然能对热点数据提供缓存服务,不会因为缓存数据的缺失而对整个系统造成冲击。

本文就Redis内置的持久化机制进行说明。


Redis持久化方式

Redis内置的持久化方式有两种:快照方式和AOF方式。快照方式是将某一时点的内存数据写到硬盘上,AOF方式是将写入的命令记录在硬盘上的文件里。下面详细说明这两种方式。


快照方式

快照方式可以将一个时点的内存数据保存到硬盘。保存快照之后Redis重启时可以读取快照文件而恢复数据,也可以使用快照来建立复制对应的Redis服务器。

快照持久化模式

既然快照是保存某一个时点的内存数据,那么就要求在进行快照时内存数据不能发生变化。关于这点Redis有两种模式:SAVE和BGSAVE。SAVE模式首先使Redis停止服务,然后将这个时点的Redis内存数据写入到硬盘中,等完成写入后Redis开始提供服务,这个过程一般会比较长,在生产环境中使用的场景较少。BGSAVE模式会使用fork命令拷贝Redis的内存,在fork过程中Redis也会停止对外服务,但这个过程非常快,在实体机或者VMWare和KVM中1G的内存拷贝大概在10-20ms,而在Xen中要稍慢些,大概在200-300ms。拷贝内存完成后,拷贝的这份内存数据开始持久化到硬盘,同时Redis也继续对外提供服务。

SAVE模式对Redis可用性影响很大,可能使Redis在一段较长时间内无法提供服务。BGSAVE模式对Redis可用性影响较小,1G的内存数据会使Redis中断服务10-20ms,这个数值在一般情况下是可以接受的,但是因为BGSAVE是使用fork机制,这就要求fork时系统的可用内存至少要和Redis占用的内存一样大。

快照的触发条件

触发Redis进行内存快照持久的条件有以下几种:

  1. 给Redis服务器发送BGSAVE命令,这将触发Redis进行BGSAVE模式的快照持久。
  2. 给Redis服务器发送SAVE命令,这将触发Redis进行SAVE模式的快照持久。
  3. Redis接收到SHUTDOWN命令或者TERM信号,将触发Redis进行SAVE模式的快照持久,之后Redis停止。
  4. 在主从结构中,当从Redis同步主Redis时间太长时,主Redis会触发BGSAVE模式的快照持久。
  5. 在配置文件的save属性中配置Redis在某个条件满足时进行持久,这会触发Redis进行BGSAVE模式的持久。例如,在配置文件中配置`save 60 10000`,意为如果在60s内发生了10000次写操作那么Redis将启动BGSAVE操作。在配置文件中可以配置多个save,当有一个save条件满足时,Redis就执行BGSAVE操作。


快照配置的参数


参数名称参数值参数解释
savem秒 n次,比如60 1000配置触发快照的条件,"60 1000"表示如果在60s内发生了1000次写操作,那么Redis就要进行持久操作
stop-writes-no-bgsave-erroryes,no配置在BGSAVE发生错误时是否停止
rdbcompressionyes,no配置是否对持久数据进行压缩
dir目录路径,比如./配置持久文件保存的目录
dbfilename持久文件名,比如dump.rdb配置持久文件名

快照存在的问题


从上面的说明可以看出,快照持久化方式是基于时间点的,如果在一次快照完成,下一次快照还没开始之前Redis崩溃了,那么上一快照之后的数据变化将会丢失。在BGSAVE模式下,如果在快照刚结束时Redis崩溃,那将会丢失内存拷贝之后的发生变化的数据。



AOF方式

AOF方式将Redis每次的写操作都保存在日志文件中,通过回放日志文件Redis即可恢复所有的数据。Redis将每次写操作的日志都保存在内存的一个缓存区中而不是即时写入硬盘,Redis提供了三种方式将内存日志同步到硬盘。

文件同步方式

  • always : Redis在每次有写操作发生时都会同步到硬盘,这种方式会给IO带来很大压力,实际中写入的速率要考虑硬盘的IO速率。
  • everysec :Redis每1秒将日志同步到硬盘,这种方式性能较好,但也意为着如果Redis崩溃那么将丢失1秒的数据。
  • no : Redis不主动控制内存缓存区和硬盘的同步,而由操作系统来控制。这种方式不可控,一般不采用。

Rewriting/compacting AOF

AOF方式各方面比较均衡,但是有个缺点:随着Redis的运行硬盘上的日志文件将会越来越大,将会占用大量硬盘空间,而且在Redis重启时也会因为日志文件太大而需要很长的启动时间。为了解决这个问题Redis提供了BGREWRITEAOF命令来重建日志。

BGREWRITEAOF运行机制

BGREWRITEAOF运行机制和BGSAVE很类似:使用fork创建拷贝进程,然后再将拷贝内存中的数据写入到临时的日志文件中,完成写入后再用rename原子操作替换掉日志文件。

BGREWRITEAOF存在的问题

BGREWRITEAOF同BGSAVE一样有着以下问题:
  • fork时要暂停Redis对外服务
  • 需要系统为fork保留内存空间
除此之外,BGREWRITEAOF还有这自己的问题:
  • 因为要替换日志文件,如果日志文件非常大,比如几十G,那么替换日志文件的时间也会比较长。


AOF配置的参数

参数名称参数值参数解释
appendonlyyes,no配置是否开启AOF持久机制 
appendfsyncalways,everysec,no配置AOF持久机制的同步策略
no-appendfsync-on-rewirteyes,no配置在重建日志时是否继续进行AOF 
auto-aof-rewrite-percentage百分比值
比如100 
配置触发重建日志的条件:当前日志大小和最后一次重建日志大小的比例,这里的"100"意为当前日志大小超过最后一次重建日志大小100%时,将可能触发重建日志操作。
auto-aof-rewrite-min-size日志文件大小
比如64mb
配置触发重建日志的条件:当前日志大小的最小值,这里的"64mb"意为当前日志超过64mb时,将可能触发重建日志操作。要注意的是:auto-aof-rewrite-percentage和auto-aof-rewrite-min-size必须同时满足才可以触发重建日志操作。
dir目录路径
比如./ 
配置持久文件保存的目录


持久化方式比较

分析了Redis的快照和AOF持久机制,在实际生产环境中部署该选择哪种方式呢?下面从Redis可用性影响、数据丢失、内存占用、IO负荷、硬盘空间占用几个维度比较各持久化方式:
持久化方式可用性影响数据丢失内存占用IO负荷硬盘空间占用
SAVE分钟级较低
BGSAVE较小分钟级较低
AOF秒级较高
AOF+BGREWRITEAOF较小秒级最高较高

从上表可以看出AOF或者AOF+BGREWRITEAOF方式在一般场景下应该是优先考虑的持久化方式。