数据持久化
Redis的持久化有两种,分别是RDB和AOF,RDB是以快照的方式保存Redis内存中在某一个时间点的所有数据,AOF是以日志的方式把写操作的命令写入到文件中。RDB生成的文件是紧凑的二进制文件,而AOF生成的文件包含了很多写操作的命令的文本,该文件可以直接以文本的方式查看。
RDB和AOF的区别:
- AOF比RDB更安全,当发生灾难时,AOF丢失的数据比RDB少。
- RDB文件比AOF文件更紧凑,也就是更小,非常适用适合备份。
- RDB恢复数据的速度比AOF更快。
1. RDB
使用BGSAVE 命令可以生成快照。在生成快照时,Redis父进程会fork出一个子进程,该子进程会将内存中的所有数据写入到一个临时文件中,等所有数据都写入完毕后,该临时文件会替换掉原来的快照文件,然后子进程会退出。由于父进程没有参与到生成快照的过程中,这完全是子进程的工作,所以在生成快照时,父进程依然可以提供服务。SAVE 命令也可以生成快照,但该命令是父进程同步地生成快照,也就是说在父进程生成快照时,会阻塞所有地客户端。该命令一般用在BGSAVE 命令遇到无法创建子进程的情况。
Redis在执行BGSAVE 命令时,如果此时正在执行生成快照的操作,或此时正在执行AOF重写的操作,那么会返回一个错误给客户端。此时可以使用BGSAVE SCHEDULE 命令,执行该命令时如果此时正在执行AOF重写操作,则会先返回成功消息给客户端,然后等到AOF重写完成后再进行快照的操作。客户端可以使用LASTSAVE 命令检查操作是否成功。
如果fork时,父进程的数据集很大,那么fork时可能会阻塞客户端比较长的一段时间,所以生成快照是很昂贵的操作。所以不能频繁地生成快照文件。当发生灾难时,快照文件会丢失从生成快照的时间点到发生灾难的时间点的所有数据。
# RDB的AOF文件保存的路径
dir /var/redis/
# 快照文件的名称,默认为dump.rdb
dbfilename dump.rdb
2. AOF
使用AOF时,Redis会把每次收到的写命令以Redis规定的格式记录到AOF文件中,当时间一长,AOF文件会很大,而且很多命令都是冗余的,如对某个key执行100次自增命令,那么这100个命令都会写入到AOF文件中。此时可以使用BGREWRITEAOF 命令来重写AOF文件,也就是清除AOF文件的冗余数据。
# 开启AOF持久化,默认为no
appendonly yes
# AOF文件的名称,默认为appendonly.aof
appendfilename "appendonly.aof"
AOF文件的内容如下图,其中* 表示一个数组,后面的数字表示数组的长度。$ 表示一个字符串,后面的数学表示下一行内容的长度。
Redis收到新命令时,有三种方式将内存中的命令写入到AOF文件中:
appendfsync always :每接收到一次新命令时就写入到AOF文件中,如果同时收到多条命令,如多个客户端或管道,则这些命令会一次写入到AOF文件中。该方式非常慢,但非常的安全。appendfsync everysec :每一秒写一次,该方式足够快,足够安全,是Redis的默认方式。如果发生灾难时,最多丢失一秒的数据。appendfsync no :将写入的操作交给操作系统来执行,Linux通常每30秒写入一次,这是最快,但最不安全的方式。
在RDB和AOF持久化都开启的情况下,Redis重启时,只会用AOF文件来重建数据集,因为AOF的数据是最完整的。
# AOF写入命令到文件的方式,默认为everysec
appendfsync everysec
当执行BGREWRITEAOF 命令时,Redis父进程会fork出一个子进程,该子进程在临时文件中写入新的AOF,同时父进程会创建一个缓存区,用来存放在重写过程中接收到的新命令。等到子进程重写完成后,会发给父进程一个通知,当父进程收到该通知后,会将缓存区中的新命令写入到临时AOF文件中,写完后该临时文件会替换掉原来的AOF文件。在父进程将新命令写入到缓存区的同时,会和原来一样将新命令写入到原来的AOF文件中,这样的话即使重写失败了,数据也是安全的。
当执行BGREWRITEAOF 命令后,如果此时Redis子进程正在生成快照文件,那么Redis服务器会将一个带有适当信息的成功消息返回给客户端,并预定BGREWRITEAOF 操作。等到快照生成完毕后,BGREWRITEAOF 操作才会被执行。Redis服务器收到BGREWRITEAOF 命令后,如果此时正在执行AOF重写,那么会返回一个错误给客户端,并且该命令不会被执行,如果AOF执行失败,则也会返回一个错误给客户端。
如果Redis收到执行快照的命令时正在执行快照,或收到AOF重写的命令时正在执行AOF重写,那么收到的命令都会失败并返回错误消息给客户端,因为连续的快照或AOF重写是没有意义并且很消耗资源的,前后两次相同的操作生成的文件变化量很微小。同时,生成快照和AOF重写不能同时进行,因为这会消耗很多磁盘I/O和CPU资源,需要错开来进行。
3. 配置RDB和AOF
1) 自动生成快照文件
可以配置在服务器启动后或生成快照后,在多少秒后至少有指定数量的key被更改后自动生成快照。比如在30秒后至少有3个key更改了则生成快照,则30秒内无论有多少个key更改了都不会生成快照,当30秒后,如果超过了3个key更改了则生成快照,如果没有超过则继续等,此后一旦key更改达到3次则立即生成快照,然后重新计时。
之所以要配置时间,而不配置每发生多少修改时就生成快照,是因为我们并不知道实际的修改了是什么情况。假设配置了每1000次修改则生成快照,那么在高并发量的情况下,如果此时的修改量为10000次每秒,则一秒内会生成10次快照,而每一次快照都是很昂贵的操作,并且,此时本来就是高并发的环境下,再频繁地执行如此昂贵的操作,无疑会严重影响性能。所以必须要配置生成快照的最短时间,只有过了这个时间后才能生成快照。
可以配置多个生成快照的条件,格式是save <最少秒数> <更改数> 。
# redis的默认配置
save 3600 1
save 300 100
save 60 10000
配置如上配置后,当Redis启动后,开始计时。在60秒内,无论如何修改key,都不会生成快照。假如在100秒时有50个key修改了,不生成快照,在70秒时有200个key修改了,不生成快照,此后不更改key,当时间到达300秒后,立马生成快照,然后重新计时,并且修改数重置为0。再假如此后3600秒内没有key修改了,则3600秒后,一旦有key修改了,则会立即生成快照。
当开启RDB后,每当Redis服务器关闭时,会自动生成快照。将save 的值设置为空字符串可以禁用RDB。
# 禁用RDB
save ""
2) 自动重写AOF文件
在启动时,Redis会记录下AOF文件的大小,此后由于写操作导致该AOF文件逐渐变大,当该大小达到指定百分比时,会触发AOF重写操作。为了使AOF文件很小时不要重写,可以配置最小重写大小,当触发AOF重写时,如果此时AOF文件的大小小于最小重写大小,则会一直等待,直到AOF文件达到指定大小时才进行重写。当重写后,Redis记录的AOF文件大小会赋值为AOF文件重写后的大小,然后基于此大小的增长百分比来触发AOF重写,如此循环往复。
例如,Redis启动时,AOF文件的大小为20mb,配置的增长百分比为100,最小重写大小为64mb,则当AOF文件增长到40mb时会触发AOF重写,但该大小小于64mb,所以AOF会一直等待,直到AOF文件的大小为64mb时才进行AOF重写操作。
# 自动重写AOF文件时的增长百分比,如果为0则表示禁用自动重写AOF功能,默认为100
auto-aof-rewrite-percentage 100
# AOF重写的最小重写大小,默认为64mb
auto-aof-rewrite-min-size 64mb
3) 其它的RDB配置
可以配置压缩快照文件,这会额外消耗一些CPU性能,但是有利于快照文件的传输。
# 压缩快照文件,默认为yes
rdbcompression yes
当Redis子进程生成快照失败时,如磁盘、权限等问题,为了让用户能够感知到快照失败,会禁用写操作,否则快照失败了用户也不知情,继续写入数据,那么这时一旦发生灾难,则会丢失上次快照到灾难发生时的所有数据。如果Redis子进程在快照失败后进行重试,则不会阻止写操作,而要等到彻底失败后才会阻止写操作。
这个操作很危险,因为它有可能会阻断业务逻辑的正常进行。在生产环境中应该设置Redis的相关监控,并禁用该功能。
# 在生成快照失败后阻止写操作,默认为yes
stop-writes-on-bgsave-error yes
在生成和加载快照文件时,可以开启检验功能,该功能在生成快照文件时,会计算该文件的检验和并添加在文件的末尾,在加载快照文件时,该功能利用快照文件末尾的检验和来检验文件内容是否出现损坏。禁用该功能时生成的检验和为0,以便告诉与加载相关的代码跳过检验。注意,该功能在生成或加载控制文件时,大约会损失10%的性能。
# 开启检验功能,默认为yes
rdbchecksum yes
4) 其它的AOF配置
为了加快AOF重写的效率,Redis在AOF重写时会和生成快照一样,把当前的快照写入到临时AOF文件中,然后把再重写期间的新命令以文本的方式写入到该临时文件中,最后替换掉原来的AOF文件。结果就是重写后的AOF文件前面是完整的快照,而快照之后就是标准的AOF内容。当恢复数据时,由于AOF文件中大部分数据都是压缩的,所以恢复的速度并标准的AOF文件更快。
在配置文件中可以开启此功能,如果关闭此功能的话,则AOF文件中全是SET 类型的命令。
# 开启AOF文件混合RDB快照的功能,默认为yes
aof-use-rdb-preamble yes
当子进程在生成快照或执行AOF重写时,会占用大量的磁盘I/O,这会影响主进程的正常AOF功能,导致主进程的AOF写入操作可能会阻塞很长的时间。如果发现Redis在生成快照或重写AOF时有延迟问题,可以配置在生成快照或AOF重写时将appendfsync 设置为none ,但注意这会导致数据的安全性降低,如果此时发生灾难,可能会丢失多达30秒的数据。
# 在生成快照或AOF重写时将appendfsync设置为none,默认为no
no-appendfsync-on-rewrite no
当AOF在写入命令的过程中由于某种原因(如系统崩溃或断电)而被截断后,可能会造成AOF文件的最后一个命令写入错误的格式。当Redis在重启并重建内存数据时,如果读取到AOF文件的最后一条不正确的命令,则默认会丢弃该命令,等正常启动后会生成相关的日志信息。在配置文件中可以配置Redis在读取到最后一掉不正确的命令时停止启动。注意,该配置只适用于AOF文件被截断,而不适用于损坏的AOF文件。
可以使用Redis官方提供的redis-check-aof 工具来修复截断的AOF文件。
# 丢弃AOF文件末尾的错误命令并正常启动,默认为yes
aof-load-truncated yes
|