
用 Redis 的 SCAN 做键巡检,最容易写错的不是连接代码,而是结束条件和统计口径。返回空数组不代表结束,COUNT 不是每页条数,遍历期间还可能读到重复键。换成集群后,还必须确认扫描覆盖的是一个节点还是整个实例。
下面给出一套只读巡检流程,适合先在测试实例验证,再迁移到生产维护窗口。它不读取业务值,也不执行删除;输出的是观察次数,不冒充某一时刻的精确键总数。
原生 Redis Cluster 的一次节点级 SCAN 不会自动遍历所有主节点,客户端支持集群重定向,也不等于支持全局遍历。
腾讯云分布式缓存数据库(兼容 Redis)的官方《集群架构全局 SCAN 使用指南》说明:通过 Proxy 扩展提供全局扫描,要求 Proxy 版本为 5.8.9 或以上。不要把 Redis 内核版本当成 Proxy 版本;接入前要核对实例架构、接入方式以及对应产品文档。
下文 Python 示例只适用于单节点,或已确认支持全局 SCAN 的代理端点。原生 Cluster 需要额外设计逐主节点遍历与拓扑变化处理,不能直接套用此脚本宣称“全实例扫描完毕”。
命令形式如下:
SCAN cursor MATCH pattern COUNT count
0,后续原样传入服务端返回的游标;不能自行加一,也不能计算完成百分比。0,才表示这一轮结束;最后一批结果仍须处理。COUNT 是工作量提示,不保证返回指定数量。MATCH 用于过滤结果,通常不是前缀索引;匹配少不等于遍历成本低。因此,if not keys: break 会漏扫。直接累加 len(keys) 则可能把重复键计算多次。
准备 Python 与 redis-py,把连接信息放入受控环境变量 REDIS_URL。地址格式为 redis:// 或启用 TLS 时的 rediss://,认证信息含特殊字符时须按 URL 规则编码。不要将真实连接串粘贴到工单、代码仓库或终端录屏里。
python -m pip install redis
python scan_audit.py保存以下内容为 scan_audit.py:
import os
import time
import redis
client = redis.Redis.from_url(
os.environ["REDIS_URL"],
socket_connect_timeout=3,
socket_timeout=3,
decode_responses=False,
)
cursor = 0
batches = 0
observations = 0
started = time.monotonic()
deadline = started + 60
try:
while True:
if time.monotonic() >= deadline:
raise TimeoutError("scan incomplete: time budget exceeded")
cursor, keys = client.scan(
cursor=cursor,
match=b"audit:demo:*",
count=100,
)
batches += 1
observations += len(keys)
# 空批次也必须继续;结束批次也必须先统计。
if cursor == 0:
break
time.sleep(0.02)
print({
"completed": True,
"batches": batches,
"observations": observations,
"elapsed_seconds": round(time.monotonic() - started, 3),
})
finally:
client.close()100、20ms 和 60s 都是示例起点,不是平台推荐阈值。时间预算在批次之间检查,并不是硬实时中断;单次请求仍受连接、读取超时及客户端行为影响。脚本遇到服务端错误会失败退出,不会打印成功结果。
使用二进制响应可避免非 UTF-8 键名导致解码失败。脚本不保留全量键集合,因此不会为了去重而额外占用与键数量成正比的客户端内存。
在独立测试库中,用唯一前缀准备三个没有过期时间的键,例如 audit:demo:1、audit:demo:2、audit:demo:3,扫描期间停止对该前缀的写入。在测试版处理分支中收集实际键名,去重后应恰好等于这三个键;不要断言某个键在第几批返回。
再把匹配条件改为确定不存在的前缀。允许出现多个空批次,但仍必须等返回游标为零才成功。扩大测试数据量后,可以观察 COUNT 改变对批次数与耗时的影响,不应断言每批恰好返回 100 条。
生产验证还要观察业务延迟、CPU、请求量和网络流量。只读不等于无成本;批间休眠只能降低客户端发起速率,不能保证单条命令延迟。
腾讯云官方文档指出,主从切换或缩容可能触发 invalid cursor(master node idx out of range)。不能吞掉异常并继续使用旧游标。上面的脚本选择直接终止,把本轮标记为不完整。
需要自动重扫时,应从零开始新一轮,设置最大重试次数,并明确旧轮统计是否丢弃。若扫描结果会触发外部任务,还必须处理重复执行。仅凭键名去重也无法区分同名键被删除后重新创建的情况,因此不能随意把只读巡检改成批量删除工具。
最后要区分两个目标:游标归零证明遍历协议完成,不证明拿到了时点快照。持续写入场景下,精确盘点应另行设计一致性边界;不要把一次 SCAN 的累计观察数当成财务式精确报表。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。