Redis之持久化方式详解
背景:Redis之所以能够在技术革新发展迅速的时代超越Memcache等其他Nosql数据库,最主要的一点是Redis提供数据持久化,能够根据持久化策略将缓存数据灵活的写到磁盘上,更好地满足了当下海量数据前提下地数据处理问题,提高了Nosql的容灾能力。
Redis提供了两种持久化的方式,分别是RDB持久化(快照)和 AOF持久化(刷盘)。
1.RDB持久化
RDB(Redis DataBase)是 Redis 默认的持久化方案。在指定的时间间隔内,执行指定次数的写操作,则会将内存中的数据写入到磁盘中。即在指定目录下生成一个dump.rdb文件。Redis重启会通过加载dump.rdb文件来恢复数据。
启动方式:
(1)save :save时只管保存,其它不管,主进程阻塞,Redis此时无法处理客户端的请求,直到save结束为止,手动保存(不建议)。
192.168.79.131:6379> save OK
(2)bgsave:Redis会在后台异步进行快照操作, 快照同时还可以响应客户端请求。
192.168.79.131:6379> bgsave Background saving started
(3) 配置文件设置:在redis.conf配置文件中设置 “ save 时间间隔 key的变化数量 ”
save 900 1 //900秒内有一个key的值发生了变化就进行一次持久化 save 300 10 //300秒内有10个key的值发生了变化就进行一次持久化 save 60 10000 //60秒内有10000个key的发生了变化就进行一次持久化
工作原理:
1)执行bgsave命令,Redis父进程判断当前是否存在正在执行的子进程,如RDB/AOF子进程,如果存在bgsave命令直接返回。
2)父进程执行fork操作创建子进程,fork操作过程中父进程会阻塞,通 过info stats命令查看latest_fork_usec选项,可以获取最近一个fork操作的耗 时,单位为微秒。
3)父进程fork完成后,bgsave命令返回“Background saving started”信息 并不再阻塞父进程,可以继续响应其他命令。
4)子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后 对原有文件进行原子替换。执行lastsave命令可以获取最后一次生成RDB的 时间,对应info统计的rdb_last_save_time选项。
5)进程发送信号给父进程表示完成,父进程更新统计信息,具体见 info Persistence下的rdb_*相关选项。
RDB文件:
RDB保存的文件是dump.rdb文件 ,位置保存在Redis的启动目录(一般不做修改的情况下)。Redis每次同步数据到磁盘都会生成一个dump.rdb文件,新的dump.rdb会覆盖旧的dump.rdb文件。
RDB的优缺点:
RDB的优点:
RDB是一个紧凑压缩的二进制文件,代表Redis在某个时间点上的数据快照。非常适用于备份,全量复制等场景。比如每6小时执行bgsave备份,并把RDB文件拷贝到远程机器或者文件系统中(如hdfs),用于灾难恢复。
Redis加载RDB恢复数据远远快于AOF的方式。
RDB的缺点:
RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作创建子进程,属于重量级操作,频繁执行成本过高。
RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个格式 的RDB版本,存在老版本Redis服务无法兼容新版RDB格式的问题。
针对RDB不适合实时持久化的问题,Redis提供了AOF持久化方式来解决。
2.AOF持久化
AOF(Append Only File),Redis 默认不开启。它的出现是为了弥补RDB的不足(数据的不一致性),所以它采用日志的形式来记录每个写操作,并追加到文件中。Redis 重启会根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。(实时备份)
启动配置:
appendonly yes|no //是否开启AOF持久化功能,默认为不开启状态 appendfsync always|everysec|no //AOF写数据策略
工作原理:
1)所有的写入命令会追加到aof_buf(缓冲区)中。
2)AOF缓冲区根据对应的策略向硬盘做同步操作。
3)随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩的目的。
4)当Redis服务器重启时,可以加载AOF文件进行数据恢复。
AOF写操作同步策略:
Redis提供了多种AOF缓冲区同步文件策略,由参数appendfsync控制;
- always(每次) 每次写入操作均同步到AOF文件中,数据零误差,性能较低
- everysec(每秒) 每秒将缓冲区中的指令同步到AOF文件中,数据准确性较高,性能较高,在系统突然宕机的情况下丢失1秒内的数据(刷盘)
- no(系统控制) 由操作系统控制每次同步到AOF文件的周期,整体过程不可控,Redis不会主动调用fsync去将AOF日志内容同步到磁盘,所以这一切就完全依赖于操作系统的调试了。对大多数Linux操作系统,是每30秒进行一次fsync,将缓冲区中的数据写到磁盘上。
no-appendfsync-on-rewrite :表示在进行aof重写期间,是否不要继续记录日志到aof文件;
- yes :代表相当于重写期间的appendfsync为no,不会把redis的写操作命令写入aof文件,这时候IO阻塞情况就不会太严重;
- no :相当于还是按照之前设置的appendfsync那样进行,可能你设置了everysec,这时候在重写aof时,也会把redis的写命令写入aof文件,这就可能会造成IO阻塞;
AOF重写机制:
由于开启aof持久化之后,每次写操作的命令都被记录到appendonly.aof文件中,随着写操作的频繁,aof持久化文件会越来越大,为了解决这个问题,Redis提供了AOF重写机制。
原理:
根据重写条件,对appendonly.aof文件进行压缩优化,降低文件大小。
启动方式:
AOF重写过程可以手动触发和自动触发:
- 手动触发:直接调用bgrewriteaof命令。
- 自动触发:根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参 数确定自动触发时机。
- auto-aof-rewrite-min-size:表示运行AOF重写时文件最小体积,默认 为64MB。
- auto-aof-rewrite-percentage:代表当前AOF文件空间 (aof_current_size)和上一次重写后AOF文件空间(aof_base_size)的比值。
- 自动触发时机=aof_current_size>auto-aof-rewrite-min size&&(aof_current_size-aof_base_size)/ aof_base_size>=auto-aof-rewrite percentage
- 其中aof_current_size和aof_base_size可以在info Persistence统计信息中查看。
重写后的AOF文件为什么可以变小?有如下原因:
1)进程内已经超时的数据不再写入文件。
2)旧的AOF文件含有无效命令,如del key1、hdel key2、srem keys、set a111、set a222等。重写使用进程内数据直接生成,这样新的AOF文件只保 留最终数据的写入命令。
3)多条写命令可以合并为一个,如:lpush list a、lpush list b、lpush list c可以转化为:lpush list a b c。为了防止单条命令过大造成客户端缓冲区溢 出,对于list、set、hash、zset等类型操作,以64个元素为界拆分为多条。
关闭AOF重写(默认开启的)
config set auto-aof-rewrite-percentage 0 //将比值设置为0,就不会自动触发重写
参考文献:
Redis开发与运维(付磊)