上一篇blog在linux中安装了Redis,并且对Redis进行了启动和操作。本篇blog主要学习下Redis的持久化策略。什么是持久化呢?举个最简单的例子,就是内存中的数据如果突然遭遇断电,将会丢失,那么为了保证数据不丢失,内存中的数据要持久化到硬盘里来,利用永久性存储介质将数据进行保存,在特定的时间将保存的数据进行恢复的工作机制称为持久化。持久化的作用就是防止数据的意外丢失,确保数据安全性!也就是为什么我们每写会儿文档就要保存一次的原因。
因为Redis本质上也是个数据库,所以也面临持久化的问题,Redis提供的持久化策略有两种,一种是RDB,也就是数据快照,一种是AOF,也就是数据日志。
RDB方案
RDB是数据快照的持久化策略,只存储数据结果,存储格式简单,关注点在数据。依据执行持久化时机分为如下三种策略:
save即时执行策略
save即时生成策略持久化的命令为save。我们执行下查看:
127.0.0.1:6379> keys * 1) "love" 127.0.0.1:6379> save OK 127.0.0.1:6379> set age 26 OK 127.0.0.1:6379> save OK 127.0.0.1:6379> set sex girl OK 127.0.0.1:6379> save OK 127.0.0.1:6379>
我们找到之前设定的log文件地址查看文件,可以看到生成了一个新的文件:
save执行原理
这就是之前大佬们老是讨论的而我一无所知的dump快照文件啊!,那么save执行的原理是什么呢?因为redis是单线程的,所以多客户端操作的时候,会有个指令执行顺序。
save指令比较耗费服务器性能!
RDB最佳配置
其实使用RDB存在一些最佳实践,我们调整下它的配置,还是在redis-6379.conf进行修改,修改后配置为:
port 6379 daemonize yes logfile "redis-6379.log" dir /root/redis-6.0.8/data/ dbfilename dump-6379.rdb rdbcompression yes rdbchecksum yes
同时我们可以把6380也同步修改了即可,修改完后杀掉进程,重启服务:
[root@192 ~]# ps -ef | grep redis- root 35924 1 0 11:28 ? 00:01:05 redis-server *:6379 root 36048 1 0 11:35 ? 00:01:04 redis-server *:6380 root 39574 39523 5 15:24 pts/0 00:00:00 grep --color=auto redis- [root@192 ~]# kill -s 9 35924 [root@192 ~]# kill -s 9 36048 [root@192 ~]# ps -ef | grep redis- root 39591 39523 0 15:25 pts/0 00:00:00 grep --color=auto redis- [root@192 redis-6.0.8]# redis-server config/redis-6379.conf [root@192 redis-6.0.8]# redis-cli -p 6379 127.0.0.1:6379> set name tml love guochengyu (error) ERR syntax error 127.0.0.1:6379> set name tmlloveguochengyu OK 127.0.0.1:6379> get name "tmlloveguochengyu" 127.0.0.1:6379> save OK 127.0.0.1:6379>
我们可以看到已经写了新的dump文件进入data了,我们把之前的删掉即可。
查看即可隐约看到文件内容:
[root@192 redis-6.0.8]# cd data/ [root@192 data]# ll 总用量 12 -rw-r--r-- 1 root root 121 10月 24 15:30 dump-6379.rdb -rw-r--r-- 1 root root 3102 10月 24 15:30 redis-6379.log -rw-r--r-- 1 root root 1447 10月 24 11:35 redis-6380.log [root@192 data]# cat dump-6379.rdb REDIS0009dis-ver6.0.8edis-bitsctime_ed-mem
bgsave后台执行策略
使用指令bgsave会使用延迟执行save策略。
[root@192 redis-6.0.8]# redis-cli 127.0.0.1:6379> set age 35 OK 127.0.0.1:6379> bgsave Background saving started 127.0.0.1:6379>
bgsave执行的这个子进程不参与redis的数据读写,可以通过查看日志文件看到这个信息:
39800:M 24 Oct 2020 15:44:54.394 * Background saving started by pid 39915 39915:C 24 Oct 2020 15:44:54.397 * DB saved on disk 39915:C 24 Oct 2020 15:44:54.397 * RDB: 0 MB of memory used by copy-on-write 39800:M 24 Oct 2020 15:44:54.408 * Background saving terminated with success
条件save后台执行策略
限定时间限定条件的save持久化:满足限定时间内key的变化数量达到指定数量则进行持久化。命令为:
save second changes
second代表指定时间,changes代表key的变化数量,如果设置为:
save 100 10
100秒内有10个key变化则进行持久化,那么如果我在100秒到期的时候只有9个key变化,则重置时间,重新从上一次持久化后的key的变化数全量统计变化值【实际上也就是9个】,也就是剩余100秒只需再等待一个key变化就能进行持久化了。
配置添加
需要在配置文件进行配置:
port 6379 daemonize yes logfile "redis-6379.log" dir /root/redis-6.0.8/data/ dbfilename dump-6379.rdb rdbcompression yes rdbchecksum yes save 10 2
配置完成后进行下实验,首先重启后台进程:
[root@192 redis-6.0.8]# ps -ef | grep redis- root 39800 1 1 15:37 ? 00:00:22 redis-server *:6379 root 40243 39523 0 16:05 pts/0 00:00:00 grep --color=auto redis- [root@192 redis-6.0.8]# kill -s 9 39800 [root@192 redis-6.0.8]# ps -ef | grep redis- root 40246 39523 0 16:05 pts/0 00:00:00 grep --color=auto redis- [root@192 redis-6.0.8]# redis-server config/redis-6379.conf
同时干掉快照文件:
然后进行实验,要记住两点,1,只有对key产生变化的才算【get不算,del和set都算】,2,同一个key的两次变化都算,因为不进行数据比对,redis不会记忆上一个变化的是什么。我们先操作一次:
127.0.0.1:6379> set name tmlhhhh OK 127.0.0.1:6379> get name "tmlhhhh" 127.0.0.1:6379> [root@192 redis-6.0.8]#
这里可以看到虽然是两条指令,但一条是get不算。我们可以看到还是没有dump文件产生:
接下来我们再操作一次:
[root@192 redis-6.0.8]# redis-cli 127.0.0.1:6379> set age 25 OK 127.0.0.1:6379>
dump文件产生了,我们可以看到:
条件save执行原理
带有条件的save的工作原理如下:
需要注意的是:
- save配置后台执行的是bgsave的操作,只是有一定的触发时间
- second和change要设置成互补的,如果是相同的则没什么意义。例如如果我业务量特别大,每10秒更新1000条数据,我设置的key太小了没什么意义,一会儿一次dump写入,要爆炸,所以设置成
save 1 100000
,也就是1秒内变化的key数量不超过100000,就不需要写入dump了,反之,如果我业务量很小,每10秒更新1条数据,但是这条数据又很重要,那么我需要尽快持久化,所以设置成save 100 1,也就是100秒内,只要有一条变化就写入dump,实际情况往往是依据业务场景来的
以上就是RDB的优化方式。
RDB三种执行策略对比
以下是三种执行RDB方式的对比:
方式 | save | bgsave | 条件save |
读写 | 同步 | 异步 | 满足条件异步 |
阻塞客户端指令 | 是 | 否 | 否 |
额外内存 | 否 | 是 | 是 |
启动新进程 | 否 | 是 | 是 |
推荐使用度 | 低 | 中 | 高 |
其实说白了,又是一个空间换时间的例子。另外说几个特殊的RDB启动时机:
- 进行全量复制时,首先需要有快照
- 重启服务Redis时,可以执行RDB:
debug reload
- 关闭服务Redis的时候可以执行RDB:
shutdown save
以上就是一些特殊的启动形式
RDB恢复文件
我们存储了快照,那么该如何验证快照能恢复回数据呢?我们先把进程杀掉,也就是把内存里的干掉,看能不能恢复回来。
[root@192 redis-6.0.8]# redis-cli -p 6379 127.0.0.1:6379> keys * 1) "name" 127.0.0.1:6379> get name "tmlloveguochengyu" [root@192 redis-6.0.8]# ps -ef | grep redis- root 39624 1 1 15:27 ? 00:00:09 redis-server *:6379 root 39782 39523 0 15:36 pts/0 00:00:00 grep --color=auto redis- [root@192 redis-6.0.8]# kill -s 9 39624 [root@192 redis-6.0.8]# ps -ef | grep redis- root 39794 39523 0 15:37 pts/0 00:00:00 grep --color=auto redis- [root@192 redis-6.0.8]# redis-server config/redis-6379.conf [root@192 redis-6.0.8]# ps -ef | grep redis- root 39800 1 0 15:37 ? 00:00:00 redis-server *:6379 root 39806 39523 0 15:37 pts/0 00:00:00 grep --color=auto redis- [root@192 redis-6.0.8]# redis-cli 127.0.0.1:6379> keys * 1) "name" 127.0.0.1:6379> get name "tmlloveguochengyu"
我们杀掉进程后重启服务端,发现数据还留存着,其实就是当我们重启服务端的时候Redis读取dump文件将数据恢复了。
RDB优缺点
优点
- RDB存储效率高【能存更多】,RDB文件是紧凑的二进制文件,存储效率高,比较适合做冷备,灾备,全量复制的场景。RDB做会生成多个文件,每个文件都代表了某一个时刻的Redis完整的数据快照,RDB这种多个数据文件的方式,非常适合做冷备,因为大量的一个个的文件,可以每隔一定的时间,复制出来;可以将这种完整的数据文件发送到一些远程的云服务、分布式存储上进行安全的存储,以预定好的备份策略来定期备份Redis中的数据;
- RDB恢复数据更快【能恢复更快】,直接基于RDB数据文件来重启和恢复Redis进程,更加快速:RDB就是一份数据文件,恢复的时候,直接加载到内存中即可;
- **RDB对Redis的读写无影响,RDB对Redis【不影响Redis】对外提供的读写服务,影响非常小,可以让Redis保持高性能,因为Redis主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可;RDB每次写,都是直接写Redis内存,只是在一定的时候,才会将数据写入磁盘中
缺点
- RDB无法做到实时持久化【可能会丢数据】,一般来说,RDB数据快照文件,都是每隔5分钟,或者更长时间生成一次,这个时候就得接受一旦Redis进程宕机,那么会丢失最近5分钟的数据;这个问题,也是RDB最大的缺点,就是不适合做第一优先的恢复方案,如果你依赖RDB做第一优先恢复方案,会导致数据丢失的比较多;
- RDB在fork子进程时消耗内存【有一些内存损耗】,RDB每次在fork子进程来执行RDB快照数据文件生成的时候,都会牺牲一些内存。
- RDB基于快照,每次读写都是全量数据,数据量大时性能较低
- RDB如果设置的dump读写时间不合适,大数据量下会有IO频繁的风险
以上就是RDB的优缺点,学习完AOF后,我们来一个整体的对比
AOF方案
AOF是独立日志的持久化策略,存储操作过程,存储格式复杂,关注点在数据的操作过程。我们依据RDB的缺点就能理解AOF的存在价值了,因为没有哪种策略是完美的,只有合适的:
- RDB无法做到实时持久化【可能会丢数据】,一般来说,RDB数据快照文件,都是每隔5分钟,或者更长时间生成一次,这个时候就得接受一旦Redis进程宕机,那么会丢失最近5分钟的数据;这个问题,也是RDB最大的缺点,就是不适合做第一优先的恢复方案,如果你依赖RDB做第一优先恢复方案,会导致数据丢失的比较多;
- RDB在fork子进程时消耗内存【有一些内存损耗】,RDB每次在fork子进程来执行RDB快照数据文件生成的时候,都会牺牲一些内存。
- RDB基于快照,每次读写都是全量数据,数据量大时性能较低
- RDB如果设置的dump读写时间不合适,大数据量下会有IO频繁的风险
基于以上问题,我们看下AOF的实现。
- 只记录部分数据,不记录全量数据
- 只记录操作过程,不记录操作数据
- 对所有操作均记录,降低丢失数据的可能性。
AOF是以独立日志的形式存在的方式记录每次执行的命令,重启时再执行AOF中记录的命令来达到恢复数据的目的,也就是改记录数据为记录日志,主要解决的就是RDB的非实时持久化的问题,现在已经是Redis持久化的主流方式,优先使用这个。