RDB 文件被磁盘、拷贝或网络传输弄坏一个字节,Redis 能发现吗?靠的是文件末尾那个 8 字节的 CRC64 校验和,以及 redis-check-rdb 这个工具。这篇故意弄坏 RDB 文件三种方式,看 Redis 与检查工具各自的反应,并量一下打开校验和要多花多少时间。
dump.rdb:5488988 字节;结尾 8 字节(CRC64)= 1b8749a5723c6a4a 退出码 0 [offset 0] Checking RDB file <实验目录> [offset 82] Selecting DB ID 0 [offset 5488988] Checksum OK [offset 5488988] \o/ RDB looks OK! \o/ [info] 200000 keys read [info] 0 expires [info] 0 already expired [info] 0 subexpires
20 万个 key 的 dump.rdb 有 5488988 字节,末尾 8 字节是校验和。redis-check-rdb 依次读完整个文件,报告 Checksum OK 和读到的 key 数。
起来了: False 退出码: 1
RDB age 0 seconds
RDB memory usage when created 12.97 Mb
Wrong RDB checksum expected: (e2a2654ddb185661) but got (4a6a3c72a549871b). Aborting now.
Internal error in RDB reading offset 5242869, function at rdb.c:5072 -> RDB CRC error
redis-check-rdb:
[offset 0] Checking RDB file <实验目录>
[offset 82] Selecting DB ID 0
--- RDB ERROR DETECTED ---
[offset 5488988] RDB CRC error
[additional info] While doing: check-sum
[info] 200000 keys read
[info] 0 expires
[info] 0 already expired
[info] 0 subexpires我用脚本找到 value-00100000 并把其中一个字符改成 X,再启动 Redis:它读完整个文件才发现校验和对不上(Wrong RDB checksum expected … but got … Aborting now),退出码 1,拒绝启动。redis-check-rdb 的诊断更直白:RDB CRC error,位置 5488988 就是文件末尾——校验和是在读完之后才比较的,所以它能告诉你「文件坏了」,不能告诉你「坏在哪一个 key」。
结尾 8 字节 = 0000000000000000(全 0 = 未计算校验和) 起来了: True DBSIZE = 200000 GET user:100000 → value-00100X00 (原值 value-00100000)
rdbchecksum no 生成的文件末尾 8 字节是 0。同样改一个字节,Redis 正常启动,DBSIZE = 200000,GET user:100000 返回被改坏的 value-00100X00。这就是 rdbchecksum no 的风险:磁盘或传输中的位翻转不会被发现——它省下的只是校验和计算的时间(见下面)。
起来了: False 退出码: 1
RDB age 1 seconds
RDB memory usage when created 12.97 Mb
Internal error in RDB reading offset 2621439, function at rdb.c:5096 -> Unexpected EOF reading RDB file
redis-check-rdb:
[offset 0] Checking RDB file <实验目录>
[offset 82] Selecting DB ID 0
--- RDB ERROR DETECTED ---
[offset 2744483] Unexpected EOF reading RDB file
[additional info] While doing: read-object-value
[additional info] Reading key 'user:196149'
[additional info] Reading type 0 (string)
[info] 99996 keys read只剩前一半的文件:Redis 报 Unexpected EOF reading RDB file;redis-check-rdb 指出出错位置、正在读的 key 和类型。结构性损坏(截断、格式错误)不依赖校验和。
rdbchecksum yes:[0.328, 0.301, 0.312, 0.3, 0.296] 中位 0.301 s rdbchecksum no :[0.286, 0.28, 0.281, 0.278, 0.298] 中位 0.281 s
100 万个 key、关闭压缩的 SAVE,每种配置连续 5 次取中位:有校验和 0.301 s,无校验和 0.281 s,差约 20 ms(约 7%)。这是本机一份小数据集(key 与 value 都很短)上的数字,数据集里 value 更大时占比会不同。为这点时间关掉校验和,通常不划算。