AOF 是追加写入的文本,崩溃时可能只写了半条命令,磁盘故障还可能让文件中间坏掉。Redis 遇到这两种情况分别怎么反应?redis-check-aof 到底修了什么?这篇故意把 AOF 文件弄坏,一步一步看启动日志、检查工具的输出,以及修复到底丢了多少数据。
incr 文件 appendonly.aof.1.incr.aof:32803 字节 起来了: True DBSIZE = 1000
aof-load-truncated yes(默认):
起来了: True DBSIZE = 999
Configuration loaded
Reading RDB base file on AOF loading...
RDB is base AOF
Done loading RDB, keys loaded: 0, keys expired: 0.
DB loaded from base file appendonly.aof.1.base.rdb: 0.000 seconds
!!! Warning: short read while loading the AOF file appendonly.aof.1.incr.aof!!!
!!! Truncating the AOF appendonly.aof.1.incr.aof at offset 32770 !!!
AOF appendonlydir/appendonly.aof.1.incr.aof loaded anyway because aof-load-truncated is enabled
aof-load-truncated no:
起来了: False 进程退出码: 1
Configuration loaded
Reading RDB base file on AOF loading...
RDB is base AOF
Done loading RDB, keys loaded: 0, keys expired: 0.
DB loaded from base file appendonly.aof.1.base.rdb: 0.000 seconds
Unexpected end of file reading the append only file appendonly.aof.1.incr.aof. You can: 1) Make a backup of your AOF file, then use ./redis-check-aof --fix <filename.manifest>. 2) Alternatively you can set the 'aof-load-truncated' configuration option to yes and restart the server.崩溃时最后一条命令只写了一半是最常见的情形。默认 aof-load-truncated yes:日志出现 short read 警告,Redis 把文件截到最后一条完整命令(offset 32770)继续启动,DBSIZE = 999。改成 no,同一个文件直接拒绝启动,日志提示用 redis-check-aof --fix。(第一次启动时 Redis 已经把文件截断了,所以我在第二次前重新放回了截断的文件。)
起来了: False 进程退出码: 1
Configuration loaded
Reading RDB base file on AOF loading...
RDB is base AOF
Done loading RDB, keys loaded: 0, keys expired: 0.
DB loaded from base file appendonly.aof.1.base.rdb: 0.000 seconds
Bad file format reading the append only file appendonlydir/appendonly.aof.1.incr.aof at offset 16303. make a backup of your AOF file, then use ./redis-check-aof --fix <filename.manifest>. Alternatively you can set the 'aof-load-corrupt-tail-max-size' configuration option to 16500 and restart the serve这是格式错误,不是尾部不完整:Redis 报 Bad file format reading the append only file … at offset 16303,退出码 1,不会带着一份不完整的数据启动。
Start checking Multi Part AOF Start to check BASE AOF (RDB format). RDB preamble is OK, proceeding with AOF tail... AOF analyzed: filename=appendonly.aof.1.base.rdb, size=89, ok_up_to=89, ok_up_to_line=1, diff=0 BASE AOF appendonly.aof.1.base.rdb is valid Start to check INCR files. 0x 3fbc: Expected prefix '$', got: 'G' AOF analyzed: filename=appendonly.aof.1.incr.aof, size=32803, ok_up_to=16303, ok_up_to_line=3509, diff=16500 AOF appendonly.aof.1.incr.aof is not valid. Use the --fix option to try fixing it.
只检查不修改:base 合法(RDB 格式,89 字节);incr 在 0x3fbc 处 Expected prefix '$', got: 'G',ok_up_to=16303,后面 16500 字节都不可信,提示用 --fix。
Start checking Multi Part AOF Start to check BASE AOF (RDB format). RDB preamble is OK, proceeding with AOF tail... AOF analyzed: filename=appendonly.aof.1.base.rdb, size=89, ok_up_to=89, ok_up_to_line=1, diff=0 BASE AOF appendonly.aof.1.base.rdb is valid Start to check INCR files. 0x 3fbc: Expected prefix '$', got: 'G' AOF analyzed: filename=appendonly.aof.1.incr.aof, size=32803, ok_up_to=16303, ok_up_to_line=3509, diff=16500 This will shrink the AOF appendonly.aof.1.incr.aof from 32803 bytes, with 16500 bytes, to 16303 bytes Continue? [y/N]: Successfully truncated AOF appendonly.aof.1.incr.aof All AOF files and manifest are valid 修复后 incr 文件 16303 字节(原 32803 字节) 起来了: True DBSIZE = 500 数据损失:500 个 key(损坏点 k500 及之后的全部命令)
--fix 要求确认,然后把 incr 文件从 32803 字节截到 16303 字节;重启后 DBSIZE = 500。修复的意思是「保留损坏点之前的部分」,损坏点之后的 500 个 key 全部丢失——即使它们本身是完好的。所以动手之前先备份。
aof-load-corrupt-tail-max-size 1000: 起来了 False,DBSIZE = None,退出码 1
Bad file format reading the append only file appendonlydir/appendonly.aof.1.incr.aof at offset 16303. make a backup of your AOF file, then use ./redis-check-aof --fix <filename.manifest>. Alternatively you can set the 'aof-load-corrupt-tail-max-size' configuration option to 16500 and restart the serve
aof-load-corrupt-tail-max-size 16500: 起来了 False,DBSIZE = None,退出码 1
Bad file format reading the append only file appendonlydir/appendonly.aof.1.incr.aof at offset 16303. make a backup of your AOF file, then use ./redis-check-aof --fix <filename.manifest>. Alternatively you can set the 'aof-load-corrupt-tail-max-size' configuration option to 16500 and restart the serve
aof-load-corrupt-tail-max-size 20000: 起来了 True,DBSIZE = 500,退出码 None
!!! Warning: corrupt AOF file tail!!!
!!! Truncating the AOF appendonlydir/appendonly.aof.1.incr.aof at offset 16303 (remaining 16500) !!!
AOF appendonlydir/appendonly.aof.1.incr.aof loaded anyway because aof-load-corrupt-tail-max-size is enabledRedis 8 增加了一个选项:允许丢弃损坏点之后最多这么多字节,然后照常启动。试了三个值:1000、16500 拒绝,20000 才通过。损坏尾部实际是 16500 字节(日志 remaining 16500),错误信息也建议设成 16500,但恰好等于它时我这里仍然拒绝——我没有去查为什么(可能是严格的「小于」比较),只能说:设置时要留出余量。这个选项让「丢弃多少」有了上限,不需要人工跑 --fix。