Redis学习-持久化(六)
前言
有时候服务器会遇到一些状况,不得不重启机器,Redis的数据都是基于内存,重启后内存中的数据就会丢失,这时候有可能出现几种场景:
(1)Redis作为数据库时,数据无法返回;
(2)Redis作为缓存时,缓存失效导致雪崩,所有的请求直接打到DB上造成服务无法响应
。。。
此时我们就希望Redis重启后能够保存重启前的数据,避免以上的情况发生,从内存中将数据同步到硬盘上,重启后可以从硬盘恢复到内存中,就是持久化过程。Redis支持两种持久化方式:快照和AOF。
快照
所谓快照,就是当符合一定条件时,Redis会将内存中的所有数据生成一份副本并存储在硬盘上,以下几种情况会触发快照:
(1)根据配置规则自动快照;
(2)用户执行SAVE或BGSAVE命令;
(3)执行FLUSHALL命令;
(4)执行复制
根据配置规则自动快照
Redis提供了配置文件,允许用户自己配置快照条件,满足条件时,触发快照,条件为时间T和影响Key的个数N,即当时间T内被写入(更新)的Key个数大于N时,满足条件触发快照,例如:
save 600 1
save 300 10
每个条件占用一行,以save开头,多个条件之间是“或”的关系,以上的例子表示,600秒内至少有1个key被写入(更新)或300秒内至少有10个key被写入(更新)时,进行快照。
用户执行SAVE或BGSAVE命令
除了满足条件自动触发快照外,当服务需要重启前或者迁移数据时,需要手工执行快照操作,Redis提供两个命令来执行:
(1)SAVE命令
当执行SAVE命令时,Redis同步执行快照,此时会阻塞所有客户端请求(类似JVM的stop the world),如果数据较多,可能导致Redis长时间不响应,所以在生产环境下尽量避免使用这个命令,以免造成服务不可用。
(2)BGSAVE命令
与SAVE命令不同的是,BGSAVE命令执行时,是以异步的方式进行快照,此时还会接收客户端的请求并作出响应,命令开始执行时会立即返回OK表示开始执行,如果要知道快照是否完成,可以通过LASTSAVE命令来获取最后一次成功快照的时间,返回的时间是Unix时间戳,例如:
redis->LASTSAVE
(integer)1423537869
执行FLUSHALL命令
执行FLUSHALL命令时,Redis会清除所有数据,此时只要定义了自动快照的条件,无论是否满足这个条件,都会执行快照。
执行复制时
在集群环境下,当Redis将数据从master复制到slave时,即使没有定义自动快照条件,且没有手工执行快照,也会执行快照生成快照文件。
快照过程
快照的文件目录和文件名可以通过dir和dbfilename两个参数来配置,默认会保存在当前进程的工作目录中的dump.rdb文件,
dbfilename dump.rdb
dir ./
下面是快照的过程:
(1)执行fork函数复制一份进程(父进程)的副本(子进城);
(2)父进程继续接收并处理客户端请求,子进程开始将内存中的数据写入硬盘中的临时文件;
(3)子进程将写入完成的临时文件替换旧的RDB文件,快照完成。
以上过程可以发现Redis在执行快照过程中不会修改RDB文件,只会写入临时文件中,只有快照结束后才会用临时文件覆盖RDB文件,这样可以保证RDB文件在任意时刻的完整性,以便于通过定时备份RDB文件来实现Redis的备份。RDB文件是经过压缩,以二进制格式存储,所占空间会小于内存中的数据大小,更利于传输和存储。
Redis启动后会先读取RDB文件,将数据从硬盘载入内存中,根据数据量大小和服务器性能的差异,这个时间也会有所不同。通过快照方式实现持久化,一旦Redis异常退出(例如断电、强杀进程等),就会丢失最后一次快照之后更改的所有数据。此时就要根据实际的应用场景,通过设置自动快照条件参数的方式将可能造成的数据丢失控制在能接收的范围内,比如Redis作为缓存,丢失最近几秒的数据或者几十个Key的数据在可接受范围内。但是如果Redis作为数据库,丢失的数据相对重要,这种情况一旦发生,损失要降到最小,则可以使用下面介绍的AOF方式进行持久化。
AOF
当使用Redis存储重要的数据时,可以打开AOF持久化配置,使Redis异常退出造成的数据损失降到最低,AOF的全称是“Append-Only File”,从字面上看就是追加到文件中,也就是Redis每执行一条写命令都会追加到硬盘文件中(这个过程会影响到Redis的性能,但大多数情况下可以忽略,AOF的性能也取决于硬盘的响应速度)。Redis默认不开启AOF,可以通过配置appendonly参数来启用
appendonly yes
开启AOF持久化后每执行一条会影响Redis数据的命令时,会将该命令追加写入AOF文件,默认情况下,AOF文件的保存位置和快照文件相同,都由dir参数配置,默认文件名为appendonly.aof,可以通过appendfilename参数配置
appendfilename "appendonly.aof" dir ./
AOF的实现
AOF是以文本字符串的方式追加命令,如执行以下命令:
set key 0
set key 1
get key
del key
因为Redis只会将影响数据的命令写入,因此第3条get命令会被忽略,此时appendonly.aof的文件内容如下:
*2 $6 SELECT $1 0 *3 $3 set $3 key $1 0 *3 $3 set $3 key $1 1 *2 $3 del $3 key
AOF文件的内容保存的是客户端与Redis通信的原始协议内容,这里还有个问题,第二条set命令覆盖了第一条set命令设置的key值,第四条del命令删除了key值,那么这四条命令相对来说是冗余的,即使aof文件不保存也不影响最终的结果,随着执行命令的增多,AOF文件的大小也会不断增大,即使内存中实际的数据可能也没有多少。我们希望减小AOF文件的大小,上面已经看到,文件中可能出现冗余的命令,此时只要设置条件,让Redis把冗余的命令删除,重写AOF文件。这个条件可以在redis.conf中配置
auto-aof-rewrite-percentage 100 //当前AOF文件大小超过上次重写时文件大小的百分比
auto-aof-rewrite-min-size 64mb //允许重写的最小AOF文件大小,AOF文件小于这个值,不重写
除了以上配置外,也可以通过BGREWRITEAOF命令手工执行AOF的重写,以上AOF文件重写后,内容是空的,因为是插入key -> 删除key,对于AOF的重写过程而言,只与内存中的数据有关,因此以上命令相当于什么也没有发生。在Redis启动时,会逐个执行AOF中的命令将硬盘中的数据载入到内存中,相对于快照的方式,速度稍慢。
虽然每次执行更改数据的操作时,AOF理论上都会将命令记录在AOF文件中,但事实上由于操作系统缓存的存在,数据并没有立即写入硬盘,而是进入了系统的硬盘缓存,每隔一段时间缓存刷新时将数据写入硬盘。如果在这间隔时间内系统异常退出也会导致硬盘缓存中的数据丢失。既然用AOF就是为了数据损失降低到最小,自然无法容忍这样的情况,因此要在AOF文件写入时主动刷新系统缓存把数据写入硬盘。可以通过appendfsync参数设置同步时机:
# appendfsync always //每次写入AOF都执行刷新 appendfsync everysec //每秒执行一次刷新 # appendfsync no //由操作系统决定何时刷新
默认情况下是everysec,既保证性能,又兼顾了数据安全。
Redis允许同时开启AOF和快照两种持久化策略。
I'm not just a coder
keep running,keep fighting...
==================================