AOF的三种策略
依据何时将命令从缓存区同步到AOF文件的时机,有以下几种策略
always写数据策略
Redis 在每个事件循环都要将 AOF 缓冲区中的所有内容写入到 AOF 文件,并且同步 AOF 文件,所以 always 的效率是 appendfsync 选项三个值当中最差的一个,但从安全性来说,也是最安全的。当发生故障停机时,AOF 持久化也只会丢失一个事件循环中所产生的命令数据。数据零误差,性能极低,不推荐使用
everysec写数据策略
Redis 在每个事件循环都要将 AOF 缓冲区中的所有内容写入到 AOF 文件中,并且每隔一秒就要在子线程中对 AOF 文件进行一次同步。从效率上看,该模式足够快。当发生故障停机时,只会丢失一秒钟的命令数据。准确性较高,性能较高,推荐使用
no写数据策略
Redis 在每一个事件循环都要将 AOF 缓冲区中的所有内容写入到 AOF 文件。而 AOF 文件的同步由操作系统控制。这种模式下速度最快,但是同步的时间间隔较长,出现故障时可能会丢失较多数据
AOF的基本操作
我们需要开启AOF的配置,同时指定AOF的操作策略,配置更新为:
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 appendonly yes appendfilename appendonly-6379.aof appendfsync everysec
杀掉进程,重新启动Redis后我们可以看到一个新的文件产生了:
然后我们操作几个命令:
[root@192 redis-6.0.8]# ps -ef | grep redis- root 41544 1 2 17:28 ? 00:00:02 redis-server *:6379 root 41572 39523 1 17:30 pts/0 00:00:00 grep --color=auto redis- [root@192 redis-6.0.8]# kill -s 9 41544 [root@192 redis-6.0.8]# ps -ef | grep redis- root 41580 39523 0 17:30 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 127.0.0.1:6379> keys * (empty array) 127.0.0.1:6379> set color red OK 127.0.0.1:6379> get color "red" 127.0.0.1:6379> [root@192 redis-6.0.8]# cd data [root@192 data]# ll 总用量 28 -rw-r--r-- 1 root root 56 10月 24 17:30 appendonly-6379.aof -rw-r--r-- 1 root root 118 10月 24 16:11 dump-6379.rdb -rw-r--r-- 1 root root 12957 10月 24 17:30 redis-6379.log -rw-r--r-- 1 root root 1447 10月 24 11:35 redis-6380.log [root@192 data]# cat appendonly-6379.aof *2 $6 SELECT $1 0 *3 $3 set $5 color $3 red [root@192 data]# redis-cli 127.0.0.1:6379> set age 55 OK 127.0.0.1:6379> [root@192 data]# ll 总用量 28 -rw-r--r-- 1 root root 86 10月 24 17:31 appendonly-6379.aof -rw-r--r-- 1 root root 115 10月 24 17:31 dump-6379.rdb -rw-r--r-- 1 root root 13307 10月 24 17:31 redis-6379.log -rw-r--r-- 1 root root 1447 10月 24 11:35 redis-6380.log [root@192 data]# cat appendonly-6379.aof *2 $6 SELECT $1 0 *3 $3 set $5 color $3 red *3 $3 set $3 age $2 55
可以看到,文件中已经写入了记录key变化的命令,当然还是变化的【set、del等,get不会记录】。
需要注意的是,启用了AOF,重启服务器就不会启动RDB快照恢复数据了,所以我们这里看到的key是空的,如果我们设置appendonly no
,重启服务器则还是可以拿到RDB的快照文件。
[root@192 redis-6.0.8]# ps -ef | grep redis- root 41484 1 2 17:25 ? 00:00:04 redis-server *:6379 root 41533 39523 0 17:28 pts/0 00:00:00 grep --color=auto redis- [root@192 redis-6.0.8]# kill -s 9 41377 -bash: kill: (41377) - 没有那个进程 [root@192 redis-6.0.8]# kill -s 9 41484 [root@192 redis-6.0.8]# redis-server config/redis-6379.conf [root@192 redis-6.0.8]# redis-cli 127.0.0.1:6379> keys * 1) "name" 2) "age" 127.0.0.1:6379>
AOF重写机制
因为 AOF 持久化是通过保存被执行的写命令来记录 Redis 状态的,所以随着 Redis 长时间运行,AOF 文件中的内容会越来越多,文件的体积也会越来越大,如果不加以控制的话,体积过大的 AOF 文件很可能对 Redis 甚至宿主计算机造成影响。为了解决 AOF 文件体积膨胀的问题,Redis 提供了 AOF 文件重写( rewrite) 功能。通过该功能,Redis 可以创建一个新的 AOF 文件来替代现有的 AOF 文件。新旧两个 AOF 文件所保存的 Redis 最终状态相同,但是新的 AOF 文件不会包含任何浪费空间的冗余命令,所以新 AOF 文件的体积通常比旧 AOF 文件的体积要小得很多
AOF重写规则
并不是所有的AOF数据都需要重写。
- 进程里超时的数据不再重写,例如进程里已经过期的一些数据就不再重写了。
- 忽略无效指令,重写时使用进程中的最终数据直接生成,这样AOF只保留最终数据生成命令。例如连续冗余的set。
- 对同一数据的多条指令进行合并,例如3次incr num,可以调整为:set num 3
满足这些条件就会触发重写,以降低AOF文件的内存占用。
AOF重写执行方式
AOF共有两种重写执行方式,都是在后台进行的,只不过一个为手动触发,一个为自动触发。
手动AOF后台重写
[root@192 redis-6.0.8]# redis-server config/redis-6379.conf [root@192 redis-6.0.8]# clear [root@192 redis-6.0.8]# redis-cli 127.0.0.1:6379> keys * (empty array) 127.0.0.1:6379> set name tml OK 127.0.0.1:6379> set name ttt OK 127.0.0.1:6379> set name 555 OK 127.0.0.1:6379> set name 666 OK 127.0.0.1:6379> set name 777 OK 127.0.0.1:6379> set age 333 OK 127.0.0.1:6379> set age 333 OK 127.0.0.1:6379> del name (integer) 1 [root@192 redis-6.0.8]# cd data [root@192 data]# ll 总用量 32 -rw-r--r-- 1 root root 214 10月 24 20:50 appendonly-6379.aof -rw-r--r-- 1 root root 114 10月 24 20:50 dump-6379.rdb -rw-r--r-- 1 root root 16504 10月 24 20:50 redis-6379.log -rw-r--r-- 1 root root 1447 10月 24 11:35 redis-6380.log [root@192 data]# cat appendonly-6379.aof *2 $6 SELECT $1 0 *3 $3 set $4 name $3 tml *3 $3 set $4 name $3 ttt *3 $3 set $4 name $3 555 *3 $3 set $4 name $3 666 *3 $3 set $4 name $3 777 *3 $3 set $3 age $3 333 del $4 name $3 [root@192 data]# ll 总用量 32 -rw-r--r-- 1 root root 237 10月 24 20:52 appendonly-6379.aof -rw-r--r-- 1 root root 114 10月 24 20:50 dump-6379.rdb -rw-r--r-- 1 root root 16504 10月 24 20:50 redis-6379.log -rw-r--r-- 1 root root 1447 10月 24 11:35 redis-6380.log [root@192 data]# redis-cli 127.0.0.1:6379> bgrewriteaof Background append only file rewriting started 127.0.0.1:6379> [root@192 data]# ll 总用量 32 -rw-r--r-- 1 root root 105 10月 24 20:54 appendonly-6379.aof -rw-r--r-- 1 root root 114 10月 24 20:50 dump-6379.rdb -rw-r--r-- 1 root root 17290 10月 24 20:54 redis-6379.log -rw-r--r-- 1 root root 1447 10月 24 11:35 redis-6380.log [root@192 data]# cat appendonly-6379.aof REDIS0009dis-ver6.0.8edis-bitsctime_ed-mem
可以看到原来set name和delete name的多次操作,appendonly-6379.aof文件大小为237字节,经过后台重写后,只合并了最后一个命令,删除了name,appendonly-6379.aof文件大小变为105字节,从后台也可以看到日志:
44507:M 24 Oct 2020 20:54:33.965 * Background append only file rewriting started by pid 44594 44507:M 24 Oct 2020 20:54:34.000 * AOF rewrite child asks to stop sending diffs. 44594:C 24 Oct 2020 20:54:34.000 * Parent agreed to stop sending diffs. Finalizing AOF... 44594:C 24 Oct 2020 20:54:34.000 * Concatenating 0.00 MB of AOF diff received from parent. 44594:C 24 Oct 2020 20:54:34.000 * SYNC append only file rewrite performed 44594:C 24 Oct 2020 20:54:34.000 * AOF rewrite: 0 MB of memory used by copy-on-write 44507:M 24 Oct 2020 20:54:34.073 * Background AOF rewrite terminated with success 44507:M 24 Oct 2020 20:54:34.073 * Residual parent diff successfully flushed to the rewritten AOF (0.00 MB) 44507:M 24 Oct 2020 20:54:34.074 * Background AOF rewrite finished successfully
配置条件AOF自动重写
自动重写触发条件如下:
第一种触发条件为绝对触发条件,第二种为增量百分比触发条件。
AOF工作流程
理解了AOF的基本操作和重写机制后,我们看下AOF执行的重写原理:
我们最常用的是everysec开启重写这种模式,我们详细看下这种模式:
RDB与AOF的区别
学习完了两种持久化机制后,我们来看下两种持久化机制的对比:
持久化方式 | RDB | AOF |
占用存储空间 | 小(数据级压缩) | 大(指令级重写) |
存储速度 | 慢 | 快 |
恢复速度 | 快 | 慢 |
数据安全性 | 会丢失数据 | 依据策略而定,最多1秒 |
资源消耗 | 高 | 低 |
启动优先级 | 低 | 高 |
选择的时候可以依据如下策略,对数据敏感选择AOF【实时】,对数据不敏感选择RDB【阶段】
持久化应用场景分析
我们分析以前的Redis持久化的场景分析,看看是否建议使用持久化的方式:
总结一下:如果数据库里存储了且存的数据比较大,那么就没必要再持久化一次了,直接从数据库读取就行,当然,如果想快速加载,可以优先使用持久化。如果数据库不存储而是只在redis里进行(轻量级数据且变化速度较快且较为重要的数据)就可以使用持久化,如果数据库不存储而是只在redis里进行并且数据不怎么重要,就不需要持久化了