Redis
的强劲性能很大程度上是由于其将所有数据都存储在了内存中,为了使
Redis数据库
在重启之后仍能保证数据不丢失,需要将数据从内存中以某种形式同步到硬盘中,这一过程就是持久化。
Redis
支持两种方式的持久化,一种是
RDB
方式,一种是
AOF
方式。可以单独使用其中一种或将二者结合使用。
1、RDB方式
RDB
方式的持久化是通过快照(
snapshotting
)完成的,当符合一定条件时
Redis
会自动将内存中的所有数据进行快照并存储在硬盘上。进行快照的条件可以由用户在配置文件中自定义,由两个参数构成:时间和改动的键的个数。当在指定的时间内被更改的键的个数大于指定的数值时就会进行快照。
RDB
是
Redis
默认采用的持久化方式,在配置文件中已经预置了
3
个条件:
**save 900 1
save 300 10
save 60 10000**
save
参数指定了快照条件,可以存在多个条件,条件之间是
“
或
”
的关系。如上所说,
save900 1
的意思是在
15
分钟(
900
秒钟)内有至少一个键被更改则进行快照。如果想要禁用自动快照,只需要将所有的
save
参数删除即可。
Redis
默认会将快照文件存储在当前目录的
dump.rdb
文件中,可以通过配置
dir
和
dbfilename
两个参数分别指定快照文件的存储路径和文件名。
理清Redis
实现快照的过程对我们了解快照文件的特性有很大的帮助。快照的过程如下。
(1
)
Redis
使用
fork
函数复制一份当前进程(父进程)的副本(子进程);
(2
)父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中
的临时文件;
(3
)当子进程写入完所有数据后会用该临时文件替换旧的
RDB
文件,至此一次快照操作完成。
在执行fork
的时候操作系统(类
Unix
操作系统)会使用写时复制(
copy-on-write
)策略,即
fork
函数发生的一刻父子进程共享同一内存数据,当父进程要更改其中某片数据时(如执行一个写命令),操作系统会将该片数据复制一份以保证子进程的数据不受影响,所以新的
RDB
文件存储的是执行
fork
一刻的内存数据。
通过上述过程可以发现Redis
在进行快照的过程中不会修改
RDB
文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候
RDB
文件都是完整的。这使得我们可以通过定时备份
RDB
文件来实现
Redis
数据库备份。
RDB
文件是经过压缩(可以配置
rdbcompression
参数以禁用压缩节省
CPU
占用)的二进制格式,所以占用的空间会小于内存中的数据大小,更加利于传输。
除了自动快照,还可以手动发送SAVE
或
BGSAVE
命令让
Redis
执行快照,两个命令的区别在于,前者是由主进程进行快照操作,会阻塞住其他请求,后者会通过
fork
子进程进行快照操作。
Redis
启动后会读取
RDB
快照文件,将数据从硬盘载入到内存。根据数据量大小与结构和服务器性能不同,这个时间也不同。通常将一个记录一千万个字符串类型键、大小为
1GB
的快照文件载入到内存中需要花费
20
~
30
秒钟。
通过RDB
方式实现持久化,一旦
Redis
异常退出,就会丢失最后一次快照以后更改的所有数据。这就需要开发者根据具体的应用场合,通过组合设置自动快照条件的方式来将可能发生的数据损失控制在能够接受的范围。如果数据很重要以至于无法承受任何损失,则可以考虑使用
AOF
方式进行持久化。
2、AOF方式
默认情况下Redis
没有开启
AOF
(
append only file
)方式的持久化,可以通过
appendonly
参数开启:
appendonly yes
开启AOF
持久化后每执行一条会更改
Redis
中的数据的命令,
Redis
就会将该命令写入硬盘中的
AOF
文件。
AOF
文件的保存位置和
RDB
文件的位置相同,都是通过
dir
参数设置的,默认的文件名是
appendonly.aof
,可以通过
appendfilename
参数修改:
appendfilename appendonly.aof
下面讲解AOF
持久化的具体实现,假设在开启
AOF
持久化的情况下执行了如下
4
个命令:
SET foo 1
SET foo 2
SET foo 3
GET foo
Redis
会将前
3
条命令写入
AOF
文件中,此时
AOF
文件中的内容如下:
*2
6
SELECT
1
0
*3
3
set
3
foo
1
1
*3
3
set
3
foo
1
2
*3
3
set
3
foo
1
3
可见AOF
文件是纯文本文件,其内容正是
Redis
客户端向
Redis
发送的原始通信协议的内容(
Redis
的通信协议会在
7.4
节中介绍,为了便于阅读,这里将实际的命令部分以粗体显示),从中可见
Redis
确实只记录了前
3
条命令。然而这时有一个问题是前
2
条命令其实都是冗余的,因为这两条的执行结果会被第三条命令覆盖。随着执行的命令越来越多,
AOF
文件的大小也会越来越大,即使内存中实际的数据可能并没有多少。很自然地,我们希望
Redis
可以自动优化
AOF
文件,就上例而言,就是将前两条无用的记录删除,只保留第三条。实际上
Redis
也正是这样做的,每当达到一定条件时
Redis
就会自动重写
AOF
文件,这个条件可以在配置文件中设置:
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
auto-aof-rewrite-percentage
参数的意义是当目前的
AOF
文件大小超过上一次重写时的
AOF
文件大小的百分之多少时会再次进行重写,如果之前没有重写过,则以启动时的
AOF
文件大小为依据。
auto-aof-rewrite-min-size
参数限制了允许重写的最小
AOF
文件大小,通常在
AOF
文件很小的情况下即使其中有很多冗余的命令我们也并不太关心。除了让
Redis
自动执行重写外,我们还可以主动使用
BGREWRITEAOF
命令手动执行
AOF
重写。
上例中的AOF
文件重写后的内容为:
*2
6
SELECT
1
0
*3
3
SET
3
foo
1
3
可见冗余的命令已经被删除了。重写的过程只和内存中的数据有关,和之前的AOF
文件无关,这与
RDB
很相似,只不过二者的文件格式完全不同。
在启动时Redis
会逐个执行
AOF
文件中的命令来将硬盘中的数据载入到内存中,载入的速度相较
RDB
会慢一些。需要注意的是虽然每次执行更改数据库内容的操作时,
AOF
都会将命令记录在
AOF
文件中,但是事实上,由于操作系统的缓存机制,数据并没有真正地写入硬盘,而是进入了系统的硬盘缓存。在默认情况下系统每
30
秒会执行一次同步操作,以便将硬盘缓存中的内容真正地
写入硬盘,在这30
秒的过程中如果系统异常退出则会导致硬盘缓存中的数据丢失。一般来讲启用
AOF
持久化的应用都无法容忍这样的损失,这就需要
Redis
在写入
AOF
文件后主动要求系统将缓存内容同步到硬盘中。在
Redis
中我们可以通过
appendfsync
参数设置同步的时机:
# appendfsync always
appendfsync everysec
# appendfsync no
默认情况下Redis
采用
everysec
规则,即每秒执行一次同步操作。
always
表示每次执行写入都会执行同步,这是最安全也是最慢的方式。
no
表示不主动进行同步操作,而是完全交由操作系统来做(即每
30
秒一次),这是最快但最不安全的方式。一般情况下使用默认值
everysec
就足够了,既兼顾了性能又保证了安全。
Redis
允许同时开启
AOF
和
RDB
,既保证了数据安全又使得进行备份等操作十分容易。此时重新启动
Redis
后
Redis
会使用
AOF
文件来恢复数据,因为
AOF
方式的持久化可能丢失的数据更少。
来源:CSDN