在之前的文章中,我们应该了解到了:Redis是一个基于内存的数据库。基于内存带给Redis非常快的速度,但是内存的数据将在关机断电后消失,而这一章就是了解Redis如何将自己的数据存储到硬盘上,从而提高系统的可靠性。
1. 持久化
Redis提供了两种持久化的方案。
- RDB,RedisDataBase,以文件方式存储Redis数据库中的内容。
- AOF,AppendOnlyFile,以文件方式存储Redis数据库所有写的命令。
这两种方法互不影响,可以同时使用,也可以单独使用或者都不使用(这种情况就要考虑好Redis的作用)。
这两组配置都在redis.conf中,这里复制一份默认配置,仅供参考。
############################## MEMORY MANAGEMENT ################################
# rdb的触发条件,前者是秒,后者是在指定时间内的写命令条数
# 如 900 1,就是每900秒有一条写命令,那么进行rdb存储。
save 900 1
save 300 10
save 60 10000
# rdb的一些配置
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
# rdb的文件名和文件所在目录
dbfilename dump.rdb
dir ./
############################## APPEND ONLY MODE ###############################
# aof 默认是关闭的
appendonly no
# aof文件名: "appendonly.aof"
appendfilename "appendonly.aof"
# 还有两个选项: always,no
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble no
1.1. RDB,快照文件存储Redis内容
RDB是redis默认的持久化方案,redis会将某个时间点上的数据进行一个快照,然后将快照以文件方式保存在磁盘中,当需要时来读取快照文件恢复数据。
例子:我们设定的条件为每天只要有一个写命令,那么进行rdb操作。
当某一天服务器突然断电,我们就可以通过读取rdb快照,恢复到断电前最近一次保存的状态,而快照之后的数据就丢失了。如果你的应用对redis的架构是DB,那么丢失一天的数据是无法忍受的;如果你仅仅将其当作一个缓存,那么丢失一天的数据是完全可以接受的。所以rdb的设置应该按照应用的需求来设置。
触发rdb的条件
- 客户端向Redis发送一条命令:BGSAVE。redis会创建一个子进程,子进程负责将快照写入硬盘,而父进程继续处理命令请求。
- 客户端向Redis发送一条命令:SAVE。redis会阻塞所有命令,执行快照操作,直到操作完成。很明显SAVE命令会大大快于BGSAVE命令,但是会造成较长时间的阻塞。
- 用户设置了save配置选项,如:save 60 1。每六十秒只要有一条写命令,redis会进行BGSAVE操作。
- Redis受到一条SHUTDOWN命令是,或者接收到标准TERM信号时,会执行一个SAVE命令,执行完毕后关闭Redis。
- 当一台Redis连接上另一个Redis,并要求复制其内容时(SYNC命令),如果主Redis没有正在执行BGSAVE,或者没有刚刚接手BGSAVE操作,那么主服务器也会执行一条BGSAVE命令。
考虑是否使用rdb快照
- 当redis中的数据十分重要时,不允许存在丢失时,我们不应该使用rdb快照,因为其大概率会丢失数据。
- 用户能否忍受快照造成的卡顿,当redis过大时,rdb快照将会造成以分钟记得卡顿,如果用户无法容忍,请不要使用rdb。
- 当你把redis仅作缓存时,当你进行小型开发时,能够容忍数据丢失时,使用rdb是一个不错得选择。
1.2 AOF持久化
aof全程Append-Only File,即添加到文件尾部;
aof持久化会将被执行的写命令写到aof文件得末尾,以此来记录数据发生的变化。当需要恢复数据时,redis挨个执行aof文件中的命令即可。
aof默认是关闭的,我们需要手动打开,打开你的redis.conf进行如下操作。
# aof 默认是关闭的,我们将其改为yes 后重启redis服务。
appendonly yes
重启redis之后,redis服务器端执行的写命令将会被写入aof文件的尾部(aof)。
当执行一条命令后,redis写入文件将会被操作系统分为若干步
- 将写入内容放入缓存中
- 操作系统认为缓存已满,将缓存刷入文件中。
当然用户可以命令操作系统将文件同步到硬盘,同步操作会一直阻塞直到指定的文件被写入硬盘为止。
aof同步命令是可以配置的,选择其同步时机。
选项 | 同步频率 |
always | 每个写命令都套同步写入硬盘,严重降低Redis的速度 |
everysec | 每秒执行一次同步,显式地将多个写命令同步到硬盘(推荐) |
no | 让操作系统来决定应该何时同步 |
选择always的话,当系统崩溃时丢失数据最少,不过遗憾的是机械磁盘在这种情况每秒只能处理大约200个写命令,固态每秒也只能几万个写命令(固态寿命与写次数相关,写得越多死的越快)。
everysec则是每秒一次,当系统崩溃时,最多丢失一秒的数据。此外,当硬盘忙于写操作时,Redis还会放慢自己的速度一遍适应硬盘的最大写入速度。
no,你不愿意把丢失的数据量交给操作系统的,相信我。此外,当缓冲区被等待写入硬盘的数据填满时,Redis的写入操作将被阻塞,并导致Redis处理命令的速度变慢。 总之不建议你使用,这里只为了介绍三个可选项而已。
AOF的缺陷:AOF的文件大小
AOF能够保证丢失少量数据(可能最多就一秒的数据),又不会造成卡顿,那么为什么默认是rdb呢?
请看以下这些redis命令。
[root@VM_0_15_centos redis-4.0.2]# redis-cli
127.0.0.1:6379> set a b
OK
127.0.0.1:6379> set a c
OK
127.0.0.1:6379> set a d
OK
127.0.0.1:6379> set a c
OK
127.0.0.1:6379> set a b
OK
127.0.0.1:6379> set a a
OK
127.0.0.1:6379> del a
(integer)1
这六条命令对redis的影响仅仅是改变a->b为没有.可是AOF会如实记录这七条命令。
如果更夸张呢?对于一个系统来说,频繁的更新是很有可能的,插入后删除的需求也很大。总而言之,无效操作的数量太多了。这必将导致AOF文件的臃肿。
redis提供的解决方案是:BGREWRITEAOF命令,当用户执行此命令时,redis会rewrite(重写)AOF文件,将AOF中冗余的命令删去,使其尽可能的小。
BGREWRITEAOF命令也可以通过配置触发:
# 默认配置:当增加了100%的大小时
auto-aof-rewrite-percentage 100
# 默认配置:当文件体积大于64MB时
auto-aof-rewrite-min-size 64mb
2. 复制
将Redis持久化是很有必要的,而随着负载量的上升,或者数据的完整性越来越重要是,用户可能需要使用复制特性。
关系数据库通常会使用一个主服务器向多个从服务器发送更新,并使用从服务器来处理所有读请求。Redis也是用了同样的方法来实现自己的复制特性。
2.1 对Redis的复制相关选项进行配置
当从服务器连接主服务器的时候,主服务器会执行BGSAVE操作。而BGSAVE操作,我们在第一部分已经讲过,不再提了。
而对于从服务器,所必须的选项只有savleof。
如果用户在启动Redis服务器的时候,制定了一个包含 slaveof host port选项的配置文件,那么Redis服务器将根据该选项给定的 IP 地址和端口号来连接主服务器。
对于一个正在运行的从服务器,用户可以使用SLAVEOF no one 命令来让服务器种植复制操作。
也可以使用SAVLEOF host port来重选一个主服务器。
2.2Redis复制的启动过程
步骤 | 主服务器操作 | 从服务器操作 |
1 | (等待命令进入) | 连接(重连)主服务器,发送SYNC命令 |
2 | 开始执行BGSAVE,并使用缓冲区记录BGSAVE之后的所有写命令 | 此时客户端对从服务器的请求,将被报错,也有可能仍返回旧数据 |
3 | BGSAVE执行完毕,发送快照给从服务器,发送的同时,执行之前缓冲的写命令 | 丢弃所有旧数据,载入接收到的快照文件 |
4 | 快照发送完毕,开始向从服务器发送存储在缓冲区里的写命令。 | 完成快照同步,开始接受主服务器的写命令 |
5 | 每执行一个写命令,发送一个相同的命令 | 接受主服务器的写命令 |
在第二步,我们可以看到Redis在执行BGSAVE时,需要缓冲区,所以我们建议主服务器只是用50%~60%的内存,剩余内存留作BGSAVE操作和写命令的缓冲区。
2.3 主从链
当读请求重要性明心高于写请求的重要性,并且读请求的数量远超出一台Redis服务器可以处理的封你为时,用户需要不断增加从服务器,而随着从服务器的增加,主服务器可能无法快速地更新所有从服务器,或者因为重连和重新同步导致系统超载。那么我们就可以使用主从链。
主从链如图所示。
3. 处理系统故障
即使软件和硬件都完美无缺,Redis系统仍有可能遇到注入断电,地震等不可抗力导致的灾难。
3.1 验证快照和AOF文件
无论是RDB还是AOF,都提供了在遇到系统故障时进行数据回复的工具。
Redis提供了两个命令程序,其可以在系统故障发生之后,检查AOF文件和快照文件的状态,并在有需要的情况下对文件进行修复。
[root@VM_0_15_centos etc]# redis-check-aof
Usage: redis-check-aof [--fix] <file.aof>
[root@VM_0_15_centos etc]# redis-check-rdb
Usage: redis-check-rdb <rdb-file-name>
redis-check-aof
当你运行这个命令时,给定了–fix 参数,那么程序将对AOF文件进行修复,修复方法很简单:
扫描给定的AOF文件,寻找不正确或者不完整的命令,当发现第一个出错命令的时候,程序会删除之后的所有命令(含出错命令)。在大多数情况下,被删除的都是AOF文件末尾的不完整的写命令。
redis-check-rdb
目前并没有办法修复出错的快照文件。原因在于快照文件本身经过了压缩,导致错误可能是分布在各个地方,无法统一处理。因此建议为重要的快照保留多个备份,并进行验证。
3.2 更换故障主服务器
当主服务器出现故障时,我们可以通过SAVE命令得到一个快照,依次将数据迁移到另一台Redis服务器上,达到更换主服务器的目标。