由于 Redis 是一个内存数据库,所谓内存数据库,就是将数据库中的内容保存在内存中,这与传统的MySQL,Oracle等关系型数据库直接将内容保存到硬盘中相比,内存数据库的读写效率比传统数据库要快的多(内存的读写效率远远大于硬盘的读写效率)。但是保存在内存中也随之带来了一个缺点,一旦断电或者宕机,那么内存数据库中的数据将会全部丢失。
为了解决这个缺点,Redis提供了将内存数据持久化到硬盘,以及用持久化文件来恢复数据库数据的功能。Redis 支持两种形式的持久化,一种是RDB快照(snapshotting),另外一种是AOF(append-only-file)。
RDB是Redis用来进行持久化的一种方式,是把当前内存中的数据集快照写入磁盘,也就是 Snapshot 快照(数据库中所有键值对数据)。恢复时是将快照文件直接读到内存里。
RDB 有两种触发方式,分别是自动触发和手动触发。
在客户端操作时,只要执行了save命令,那么就会拍一次快照,将此次的数据全部存储到指定的文件中
127.0.0.1:6379> save
OK
dbfilename
:设置本地数据库文件名,默认值为 dump.rdbdir
:设置存储.rdb文件的路径rdbcompression
:设置存储至本地数据库时是否压缩数据,默认为 yes,采用 LZF 压缩,通常默认为开启状态,如果设置为no,可以节省 CPU 运行时间,但会使存储的文件变大(巨大)rdbchecksum
:默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但这样做会消耗大约10%的性能,如果希望获取到最大的性能提升,可以关闭此功能。bind 127.0.0.1
port 6379
logfile "6379.log"
dir /root/redis-4.0.11/data
dbfilename dump-6379.rdb
rdbcompression no
rdbchecksum no
daemonize yes # 后台启动
使用save命令:此命令会使用Redis的主线程进程同步存储,阻塞当前的Redis服务器,造成服务不可用,直到RDB过程完成。无论当前服务器数据量大小,线上不要用。
使用bgsave命令:此命令会通过fork()
创建子进程,在后台进程存储。只有fork阶段会阻塞当前Redis服务器,不必到整个RDB过程结束,一般时间很短。因此Redis内部涉及到RDB都采用bgsave命令。
127.0.0.1:6379> bgsave
一般我们是不会直接用命令生成RDB文件的,Redis支持自动触发RDB持久化机制,配置都在redis.conf文件里面。
save seconds count
save 900 1
save 300 10
save 60 10000
save 900 1
:900秒持久化一次,但900秒内必须至少有1个key发生变化才会持久化。
save 300 10
:300秒持久化一次,但300秒内必须至少有10个key发生变化才会持久化。
save 60 10000
:60秒持久化一次,但60内必须至少有10000个key发送变化才会持久化。
tips:实际开发可能会有偏差,如
save 60 5
,可能60秒还未到设置了5个key就发生触发一次,或者60秒内设置了4个key就触发了一次。
自动持久化底层采用的是bgsave指令。
方式 | save指令 | bgsave指令 |
---|---|---|
读写 | 同步 | 异步 |
阻塞客户端指令 | 是 | 否 |
额外消耗内存 | 否 | 是 |
启动新进程 | 否 | 是 |
debug reload
shutdown save
AOF(append only file)持久化:AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态,也就是每当 Redis 执行一个改变数据集的命令时(比如 SET), 这个命令就会被追加到 AOF 文件的末尾。
AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式
redis的AOF功能默认是关闭的,需要我们手动开启:
bind 127.0.0.1
port 6379
logfile "6379.log"
dir /root/redis-4.0.11/data
rdbcompression yes
rdbchecksum yes
daemonize no
appendonly yes
appendfsync everysec
appendfilename appendonly-6379.aof
appendonly
appendfsync
appendfilename:aof文件名称
dir:aof文件路径
注意:AOF只会保存服务器所执行的写(set,del,add 等)的命令,对于其他对结果集并没有造成影响的命令是不会写入aof文件的。如(get、hget、lrang等)
AOF 持久化是通过保存被执行的写命令来记录数据库状态的,所以AOF文件的大小随着时间的流逝一定会越来越大,其中就包含了很多不必要的命令,如set某个key两次,其结果肯定为最后一次,那么前面一次的命令就没有必要再记录下来。
为了解决此问题,Redis引入了AOF重写机制用于压缩aof文件大小,并且可以提高数据恢复的效率。
当执行AOF重写时,这个函数会进行大量的写入操作,所以调用这个函数的线程将被长时间的阻塞,因为Redis服务器使用单线程来处理命令请求,那么重写AOF期间,服务器将无法处理客户端发送来的命令请求;因此redis底层采用子进程的方式来将数据同步到aof文件当中。
思考:子进程在进行AOF重写期间,服务器进程还要继续处理命令请求,而新的命令可能对现有的数据进行修改,这会让当前数据库的数据和重写后的AOF文件中的数据不一致吗?
答:不会;
解决方案:
重写条件:
进程内已超时的数据不再写入文件
忽略无效指令,重写时使用进程内数据直接生成,这样新的AOF文件只保留最终数据的写入命令,如:
set age 20
set age 30
set age 40
最终合并为:
set age 40
对同一数据的多条写命令合并为一条命令,如:
rpush list a
rpush list b
rpush list c
rpush list d
最终合并为:
rpush list a b c d
AOF重写分为两种,一种为自动重写,另一种为手动重写。
1)手动重写
bgrewriteaof
执行完该命令后,会发现.aof文件变小了(前提是具备重写条件)。
2)自动重写
条件参数:
在redis内部会自动维护以下几个参数:
自动重写触发条件:
1、aof_current_size
大于auto-aof-rewrite-min-size
时将会触发重写
2、(aof_current_size-aof_base_size)
/aof_base_size
大于等于auto-aof-rewrite-percentage
时将会触发重写。
执行info Persistence
命令,查看当前参数
127.0.0.1:6379> info Persistence
# Persistence
loading:0
rdb_changes_since_last_save:11
rdb_bgsave_in_progress:0
rdb_last_save_time:1585142012
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
rdb_last_cow_size:0
aof_enabled:1
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:0
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
aof_last_cow_size:6385664
aof_current_size:138
aof_base_size:138
aof_pending_rewrite:0
aof_buffer_length:0
aof_rewrite_buffer_length:0
aof_pending_bio_fsync:0
aof_delayed_fsync:0
bind 127.0.0.1
port 6379
# logfile "6379.log"
dir /root/redis-4.0.11/data
#dbfilename drum-6379.rdb
#rdbcompression yes
#rdbchecksum yes
# save 1 1
daemonize no
appendonly yes
appendfsync everysec
appendfilename appendonly-6379.aof
auto-aof-rewrite-min-size 100
RDB
AOF
优点
flushall
指令,只要aof文件没有被重写,此时可以编辑aof文件删除flushall
指令,来恢复数据:*1
$7
flushdb
删除以上数据,进行AOF恢复;
缺点