
用 Redis 做缓存巡检时,常见错误不是不会调用 SCAN,而是把它当成分页查询:空列表代表结束,COUNT 100 代表每页最多 100 个,遍历数量代表准确库存。这三个判断都不成立。
可靠的只读巡检应先确认扫描范围,再把返回游标为 0 作为正常结束条件;接受重复结果,对执行时间设置预算,并把异常中断与正常完成分开记录。本文给出单机或已确认支持全局扫描的代理入口示例,不执行删除操作。
原生 Redis Cluster 的单节点 SCAN 不是全局遍历,不能因为客户端支持重定向,就默认扫描覆盖所有主节点。
腾讯云《集群架构全局 SCAN 使用指南》说明:分布式缓存数据库的集群架构通过 Proxy 扩展扫描能力,Proxy 5.8.9 及以上支持不限定节点的全局扫描。这个版本要求不能直接套用到所有 Redis 服务、直连节点或其他代理。
开始前应记录实例架构、连接入口、Proxy 版本和所选数据库。若不能确认覆盖范围,就先停止“全量巡检”的结论输出;不要拿一个节点的数据量解释整套集群。
MATCH 后,本批次可能没有匹配项,但游标仍非零,必须继续。因此,累计返回次数只能命名为“观测次数”。将所有 Key 放进客户端集合虽然能去重,却消耗与 Key 数量相关的内存,依然无法把动态扫描变成时点快照。
另外,MATCH 不是前缀索引。匹配结果很少,不代表服务端只做了很少工作。
以下示例使用 Python 和 redis-py。先在隔离测试实例安装依赖,再通过环境变量注入连接地址;地址可能包含凭证,不能写入仓库或日志。TLS、账号权限和网络连通性按实例要求配置,不要为了跑脚本开放公网访问。
python -m pip install redis
python scan_audit.py将下面代码保存为 scan_audit.py,运行前设置 REDIS_URL。SCAN_PATTERN 默认只匹配演练前缀,避免一开始就输出业务 Key。
import os
import time
import redis
client = redis.Redis.from_url(
os.environ["REDIS_URL"],
decode_responses=False,
socket_connect_timeout=3,
socket_timeout=3,
)
pattern = os.environ.get("SCAN_PATTERN", "audit-demo:*")
deadline = time.monotonic() + 60
cursor = 0
batches = 0
observations = 0
completed = False
try:
while True:
if time.monotonic() >= deadline:
raise TimeoutError("scan budget exceeded")
cursor, keys = client.scan(
cursor=cursor, match=pattern, count=100
)
batches += 1
observations += len(keys)
# 这里只统计观测次数,不读取 Value,也不输出 Key。
if cursor == 0:
completed = True
break
time.sleep(0.02)
finally:
client.close()
print({
"completed": completed,
"batches": batches,
"observations": observations,
})代码刻意不捕获异常后继续成功路径:连接失败、权限不足或游标失效都会让进程报错,并留下 completed=False。60 秒是循环检查的执行预算,不是硬实时截止;正在执行的请求及客户端重试可能让实际耗时超过预算。
这里的 COUNT 100 和每批间隔只是保守演练起点,不是生产推荐配额。上线时观察业务延迟与实例负载,再调整工作量;“只读”并不等于没有资源成本。
在没有并发写入的隔离实例中准备三个 Key:
redis-cli -u "$REDIS_URL" SET audit-demo:1 a
redis-cli -u "$REDIS_URL" SET audit-demo:2 b
redis-cli -u "$REDIS_URL" SET unrelated:1 c运行脚本,正常完成应看到 completed=True。如果要核对具体集合,可以在这个小规模演练中临时收集返回 Key,并断言去重后恰好为两个目标 Key;不要把该集合方案直接复制到百万级生产巡检。
验证循环边界时,还需要覆盖“游标非零、结果为空”的响应,以及最后一批“游标为零、仍有结果”的响应。前者必须继续,后者必须先处理结果再退出。不要依赖一次真实扫描恰巧产生这两种情况,也不要把某个游标数值写死成预期分页序号。
腾讯云文档提示,主从切换或缩容可能触发 invalid cursor(master node idx out of range)。此时不能忽略错误后继续使用旧游标。
本文脚本选择直接失败。若业务要求自动恢复,可以在外层设置有限重启次数,每次从 0 开始,并单独记录该轮统计;不能把失败轮与成功轮的观测次数相加后称为唯一 Key 数。
如果后续要基于扫描结果清理缓存,还要解决另一个竞态:扫描读到旧 Key 后,业务可能已经用同名 Key 写入新数据。直接删除名称并不一定安全。应采用版本化命名或原子条件校验等业务协议,而不是把“重复删除通常无害”当作并发安全证明。
最终验收标准应写清楚:入口范围已确认、游标正常归零、异常未被吞掉、指标名称不冒充快照统计。做到这些,巡检结果才有可解释的边界。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。