# 生成redis命令保存于afile for i in `seq 1 1000000` do echo set n$i $i >> afile done # 导入afile redis-cli -p 6380 -a zyadmin < afile # 会话1执行save的同时会话2执行命令 ## 会话1 [root@ToBeRoot ~]# redis-cli -p 6380 -a zyadmin 127.0.0.1:6380> dbsize (integer) 9495274 127.0.0.1:6380> save OK (6.46s) ## 会话2中的set命令在会话1的save执行成功后才会开始执行 [zyadmin@ToBeRoot ~]$ redis-cli -p 6380 -a zyadmin 127.0.0.1:6380> set d 1 OK (5.91s) # 会话1执行bgsave的同时会话2执行命令 [root@ToBeRoot ~]# redis-cli -p 6380 -a zyadmin 127.0.0.1:6380> bgsave Background saving started # 查看日志 [zyadmin@ToBeRoot log]$ tail -f redis6379.log 6110:M 13 Oct 11:36:23.066 * Background saving started by pid 6160 6160:C 13 Oct 11:36:28.789 * DB saved on disk 6160:C 13 Oct 11:36:28.796 * RDB: 0 MB of memory used by copy-on-write 6110:M 13 Oct 11:36:28.875 * Background saving terminated with success [root@ToBeRoot ~]# ps -ef|grep redis-serve[r] root 6110 1 6 11:32 ? 00:00:28 redis-server 127.0.0.1:6380 # 会话2没有被阻塞 [zyadmin@ToBeRoot ~]$ redis-cli -p 6380 -a zyadmin 127.0.0.1:6380> set e 2 OK
无论是save还是bgsave每执行一次都会将当前数据库状态写入磁盘。(全备)
自动间隔性保存
配置文件
save 900 1 #刷新快照到硬盘中,必须满足两者要求才会触发,即900秒之后至少1个关键字发生变化。 save 300 10 #必须是300秒之后至少10个关键字发生变化。 save 60 10000 #必须是60秒之后至少10000个关键字发生变化。 stop-writes-on-bgsave-error yes #后台存储错误停止写。 rdbcompression yes #使用LZF压缩rdb文件。 rdbchecksum yes #存储和加载rdb文件时校验。 dbfilename dump.rdb #设置rdb文件名。 dir ./ #设置工作目录,rdb文件会写入该目录。
save 900 1 #刷新快照到硬盘中,必须满足两者要求才会触发,即900秒之后至少1个关键字发生变化。 save 300 10 #必须是300秒之后至少10个关键字发生变化。 save 60 700 #必须是60秒之后至少700个关键字发生变化。 mysql> select 12124/(unix_timestamp(now())-1507867811)*60; +---------------------------------------------+ | 12124/(unix_timestamp(now())-1507867811)*60 | +---------------------------------------------+ | 711.7808 | +---------------------------------------------+ # 这种配置非常消耗IO,如果redis服务器每分钟的脏数据在711,那么这样的save配置会每分钟刷盘一次。刷盘太过频繁会影响IO # 将刷盘频率控制在2分钟一次,则2分钟大概会产生1422个dirty key save 900 1 #刷新快照到硬盘中,必须满足两者要求才会触发,即900秒之后至少1个关键字发生变化。 save 300 10 #必须是300秒之后至少10个关键字发生变化。 save 60 1400 #必须是60秒之后至少1400个关键字发生变化 # 满足N-L>=60 or dirty>= 1400 就会刷盘 # 思考会丢数据吗? 比如从上一次刷盘到现在已经过去59秒,脏key为10000个,服务器宕机,则丢失这10000个key; 比如从上一次刷盘到现在已经过去60秒,脏key为699个,服务器宕机了,则丢失699个key。
如果Redis用作缓存,例如用于Session保存,不推荐快照保存,对整体的性能影响会很大。
实践:关闭自动关闭 RDB 功能
# 永久生效 1. 修改配置文件,注释掉save的行 2. 重启服务 # 当前实例生效 1. 关闭 RDB 功能 config set save "" [root@ToBeRoot test]# redis-cli -p 6380 -a zyadmin 127.0.0.1:6380> config get save 1) "save" 2) "900 1 300 10 60 10000" 127.0.0.1:6380> config set save "" OK 127.0.0.1:6380> config get save 1) "save" 2) ""
读懂RDB文件
查看RDB文件
# 清空当前数据 [root@ToBeRoot 6379]# redis-cli -p 6380 -a zyadmin 127.0.0.1:6380> flushdb OK (5.27s) 127.0.0.1:6380> dbsize (integer) 0 127.0.0.1:6380> exit # 通过od -c 将二进制转为字符查看 dump.rdb文件 [root@ToBeRoot 6379]# od -c dump.rdb | head -n 20 0000000 R E D I S 0 0 0 7 372 \t r e d i s 0000020 - v e r 005 3 . 2 . 9 372 \n r e d i 0000040 s - b i t s 300 372 005 c t i m e 302 0000060 357 Q 340 Y 372 \b u s e d - m e m 302 230 0000100 036 \t \0 377 272 323 8 236 A 003 253 I 0000114
[root@ToBeRoot 6379]# od -cx dump.rdb 0000000 R E D I S 0 0 0 7 372 \t r e d i s 4552 4944 3053 3030 fa37 7209 6465 7369 0000020 - v e r 005 3 . 2 . 9 372 \n r e d i 762d 7265 3305 322e 392e 0afa 6572 6964 0000040 s - b i t s 300 372 005 c t i m e 302 2d73 6962 7374 20c0 05fa 7463 6d69 c265 0000060 357 Q 340 Y 372 \b u s e d - m e m 302 230 51ef 59e0 08fa 7375 6465 6d2d 6d65 98c2 0000100 036 \t \0 377 272 323 8 236 A 003 253 I 091e ff00 d3ba 9e38 0341 49ab
RDB文件结构
格式
Header
Body
Footer
字节
5
4
长度不固定
长度不固定
长度不固定
1
8
功能
Magic String
db_version
DB Selector
AUX Fields
Key-Value
EOF
checksum
空库
R E D I S
0 0 0 7
372 \t
r e d i s - v e r 005 3 . 2 . 9 372 \n r e d i s - b i t s 300 372 005 c t i m e 302 357 Q 340 Y 372 \b u s e d - m e m 302 230 036 \t \0
# 插入key并刷盘 [root@ToBeRoot 6379]# redis-cli -p 6380 -a zyadmin 127.0.0.1:6380> set name booboo OK 127.0.0.1:6380> get name "booboo" 127.0.0.1:6380> save OK # 查看dump.rdb [root@ToBeRoot 6379]# od -c dump.rdb 0000000 R E D I S 0 0 0 7 372 \t r e d i s 0000020 - v e r 005 3 . 2 . 9 372 \n r e d i 0000040 s - b i t s 300 372 005 c t i m e 302 0000060 p q 340 Y 372 \b u s e d - m e m 302 330 0000100 276 \t \0 376 \0 373 001 \0 \0 004 n a m e 006 b 0000120 o o b o o 377 N 1 335 343 y 370 V 352 0000136 # 376 \0 373 001 \0 \0 004 n a m e 006 b o o b o o # 376 \0 = select 0 # \0 004 n a m e 006 b o o b o o # 字符串类型 4字节的 name 6字节的 booboo
127.0.0.1:6380> bgrewriteaof Background append only file rewriting started # 日志 6110:M 13 Oct 16:32:53.090 * Background append only file rewriting started by pid 7833 6110:M 13 Oct 16:32:53.115 * AOF rewrite child asks to stop sending diffs. 7833:C 13 Oct 16:32:53.115 * Parent agreed to stop sending diffs. Finalizing AOF... 7833:C 13 Oct 16:32:53.115 * Concatenating 0.00 MB of AOF diff received from parent. 7833:C 13 Oct 16:32:53.115 * SYNC append only file rewrite performed 7833:C 13 Oct 16:32:53.116 * AOF rewrite: 0 MB of memory used by copy-on-write 6110:M 13 Oct 16:32:53.139 * Background AOF rewrite terminated with success 6110:M 13 Oct 16:32:53.139 * Residual parent diff successfully flushed to the rewritten AOF (0.00 MB) 6110:M 13 Oct 16:32:53.139 * Background AOF rewrite finished successfully
AOFREWRITE重写的原理
时间
服务器进程(父进程)
子进程
T1
执行命令set name a
T2
执行命令set age 10
T3
执行命令set time 2
T4
执行命令BGREWRITEAOF,创建子进程,执行AOF文件重写
开始AOF重写
T5
执行命令set a 1
执行重写操作
T6
执行命令set b 2
执行重写操作
T7
执行命令set c 3
完成AOF文件重写,向父进程发送信号
T8
接受到子进程发送的信号,将命令set a 1、set b 2、set c 3追加到新AOF文件的末尾
T9
用新AOF文件覆盖旧AOF文件
以上就是AOF后台重写,也即是BGREWRITEAOF命令的实现原理。
读懂AOF文件
[root@ToBeRoot 6379]# cat appendonly.aof *2 $6 SELECT $1 0 *3 $3 SET $4 name $6 booboo