*Redis CF.SCANDUMP 命令

CF.SCANDUMP 开始增量保存 Cuckoo Filter,适用于大型过滤器无法通过标准 DUMP/RESTORE 迁移的场景。


*语法

CF.SCANDUMP key iterator

*参数说明

参数 类型 必填 说明
key String 要保存的 Cuckoo Filter 键名
iterator Integer 迭代器值,首次调用传 0,后续调用传上次返回的迭代器值

*返回值

返回一个包含两个元素的数组:

  • [Integer, Bulk string]:迭代器值和当前数据块
  • [0, Nil]:迭代器返回 0 表示所有数据块已传输完毕

特殊情况: - Simple error reply:参数无效、键未找到或键类型错误时返回


*时间复杂度

O(n),其中 n 是过滤器的容量。


*示例

*基本用法(增量保存)

> CF.RESERVE cf 8
OK
> CF.ADD cf item1
(integer) 1
> CF.SCANDUMP cf 0
1) (integer) 1
2) "\x01\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14\x00\x01\x008\x9a\xe0\xd8\xc3\x7f\x00\x00"
> CF.SCANDUMP cf 1
1) (integer) 9
2) "\x00\x00\x00\x00\a\x00\x00\x00"
> CF.SCANDUMP cf 9
1) (integer) 0
2) (nil)

*完整备份与恢复流程

> CF.RESERVE cf 1000
OK
> CF.INSERT cf ITEMS a b c d e
1) (integer) 1
2) (integer) 1
3) (integer) 1
4) (integer) 1
5) (integer) 1

# 备份
> CF.SCANDUMP cf 0
1) (integer) 1
2) "\x01\x00\x00\x00..."
> CF.SCANDUMP cf 1
1) (integer) 9
2) "\x00\x00\x00\x00..."
> CF.SCANDUMP cf 9
1) (integer) 0
2) (nil)

# 恢复到新键
> CF.LOADCHUNK cf_backup 1 "\x01\x00\x00\x00..."
OK
> CF.LOADCHUNK cf_backup 9 "\x00\x00\x00\x00..."
OK
> CF.MEXISTS cf_backup a b c
1) (integer) 1
2) (integer) 1
3) (integer) 1

*Python 完整示例

# 增量保存过滤器
chunks = []
iter = 0
while True:
    iter, data = CF.SCANDUMP(key, iter)
    if iter == 0:
        break
    else:
        chunks.append([iter, data])

# 保存 chunks 到文件或传输到另一台服务器

# 加载过滤器
for chunk in chunks:
    iter, data = chunk
    CF.LOADCHUNK(new_key, iter, data)

*常见错误

错误 原因 解决
ERR wrong number of arguments 参数数量不足 提供 key 和 iterator 两个参数
ERR not found 键不存在 先创建 Cuckoo Filter
ERR item exists 键已存在但不是 Cuckoo Filter 类型 使用不同的键名

*最佳实践

  • 首次调用传 0:第一次调用 CF.SCANDUMP 时 iterator 必须是 0,表示从头开始扫描
  • 顺序保存:必须按返回的迭代器顺序依次调用,直到返回 0 为止。不能跳过或乱序处理数据块
  • 配合 CF.LOADCHUNK 使用:保存的 (iterator, data) 对需要原样传递给 CF.LOADCHUNK 进行恢复
  • 数据一致性:在增量保存过程中,不要修改源过滤器(如插入或删除元素),否则可能导致恢复后的数据不一致
  • 大数据迁移:对于超过 1MB 的大型 Cuckoo Filter,推荐使用 CF.SCANDUMP + CF.LOADCHUNK 替代 DUMP/RESTORE,因为后者可能因单次传输数据过大而失败
  • 分块存储:可以将每个 (iterator, data) 对分别存储到文件或数据库中,便于后续分批恢复

*FAQ

Q1: CF.SCANDUMP 和 DUMP 命令有什么区别? A: DUMP 是 Redis 通用命令,将整个键序列化为单个二进制字符串。对于大型 Cuckoo Filter(如数百万元素),DUMP 可能产生巨大的数据块,导致内存或网络问题。CF.SCANDUMP 将过滤器分成多个小块增量输出,更适合大型过滤器的备份和迁移。

Q2: 迭代器值 0 表示什么? A: 当 CF.SCANDUMP 返回迭代器值为 0 时,表示所有数据块已经传输完毕,增量保存完成。首次调用时传入 0 表示从头开始扫描,与返回 0 的含义不同。

Q3: 数据块可以分批保存吗? A: 可以。每次调用 CF.SCANDUMP 获取一个数据块后,可以立即保存到磁盘或传输到远端,然后再调用下一次。不需要在内存中保存所有数据块。只要在恢复时按相同顺序加载即可。

Q4: 保存过程中修改过滤器会怎样? A: 如果在 CF.SCANDUMP 过程中修改过滤器(插入或删除元素),可能导致恢复后的过滤器不一致。建议在保存期间冻结过滤器的写入操作,或使用复制实例进行备份。

Q5: 数据块大小固定吗? A: 不固定。数据块大小取决于过滤器的容量和当前状态。通常情况下,每个数据块的大小相对较小(KB 级别),适合网络传输。可以通过 CF.INFO 查看 Size 字段估算总数据量。