当前位置: 首页 > news >正文

Redis之Keys命令和Scan命令

序言

网上看到的面试题:Redis有1亿个key,其中10w个key是以某个固定的前缀开头,如何将它们全部找出来?一般有两种命令可以实现:

  • Keys命令
  • Scan命令

下面具体分析一下两种命令

Keys命令

Keys pattern

如下图所示,建了一些不同数据结构(String、Hash、List、Set、ZSet)的Key,使用命令找出前缀为prefix的Key(key区分大小写),
在这里插入图片描述

  • 时间复杂度O(n);
  • 笔记本电脑40毫秒内可以查100w个键值对;
  • 生产环境慎用,大型数据库上执行会影响性能;

那么在大型数据库场景下为什么不能使用该命令呢?

Keys命令是一个阻塞式操作。

  • 单线程模型:Redis的命令处理是基于单线程的。一个命令在执行时,其他所有客户端的请求都必须等待;
  • 全量遍历:Keys为了找出所有匹配的key,会遍历数据库(NoSQL)中所有的key,遍历完成之前,Redis无法处理任何其他命令。
  • 生产环境灾难:如果正在有1亿个key的实例上执行Keys命令,会导致Redis服务卡顿数十秒甚至数分钟,所有依赖Redis的业务都会出现超时和雪崩,会导致严重的生产事故。

Scan命令

SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]

在这里插入图片描述

  • 单次调用时间复杂度O(1),完整迭代时间复杂度O(n);所以单次调用不会长时间阻塞线上服务;
  • 非阻塞式(渐进式)迭代:该命令允许增量迭代,每次调用返回少量数据,然后返回一个游标(cursor),下次传入这个游标,Redis就会接着上次结束的地方继续扫描,如上图scan xxx match prefix* count 3每次返回的游标不一定按照顺序;
  • COUNT参数:COUNT是一个建议值,告诉Redis希望每次迭代返回大约多少个key。但不是精确的,有时多有时少,但是可以控制单次扫描的粒度。如上图scan xxx match prefix* count 3每次返回的数据量不一定都是3;

参看官网,相关的还有其他的一些扫描指令:

  • SSCAN:iterates elements of Sets types.(针对Set数据结构)
  • HSCAN:iterates fields of Hash types and their associated values.(针对Hash数据结构)
  • ZSCAN:iterates elements of Sorted Set types and their associated scores.(针对ZSet数据结构)

在这里插入图片描述

实际操作

实际项目中可能会通过python脚本或者LUA脚本去执行查找,下面是使用python代码去执行的示例代码,

import redisr = redis.Redis(host='localhost', port=6379)
cursor = 0
prefix = 'your_prefix:*'
found_keys = []while True:cursor, keys = r.scan(cursor, match=prefix, count=10000)found_keys.extend(keys)if cursor == 0:break

可以使用Lua脚本在Redis服务器端直接处理,减少网络往返:

local keys = redis.call('SCAN', ARGV[1], 'MATCH', ARGV[2], 'COUNT', ARGV[3])
return keys

其他思路

空间换时间

在这里插入图片描述

另外维护一个“索引”:

  • 创建Key时,将key添加到前缀索引的Set集合中;
  • 查找Key时,直接读取索引Set的所有成员,这样时间复杂度即使是O(n),遍历的也是10w数据,而非NoSQL数据库中的1亿条数据;
  • 删除时,除了删除原始key,还需要从索引Set中移除对应的成员;

从节点(Replica)执行

假设这是一个低频且用于离线分析的需求,并且不想修改现有的数据结构,可以考虑在Redis集群(主从、哨兵、集群模式)的从节点去执行SCAN命令操作(甚至Keys命令),避免长时间耗时影响主节点(Master)的正常读写。
在这里插入图片描述

http://www.dtcms.com/a/351322.html

相关文章:

  • 后端Web实战-部门管理开发
  • BA 楼宇自控系统 + AI:重构楼宇设备管理的 “智能决策” 体系
  • 『专利好药用力心脑血管健康』——爱上古中医(28)(健康生活是coder抒写优质代码的前提条件——《黄帝内经》伴读学习纪要)
  • 阿里云 ECS 可观测性最佳实践
  • 【Canvas与旗帜】上三常之中国
  • PMP项目管理知识点-⑧ 项⽬质量管理
  • 【传奇开心果系列】Flet框架实现的图形化界面的PDF转word转换器办公小工具自定义模板
  • sed截取慢SQL大文件并导出指定时间范围内容
  • 数据结构(时空复杂度)
  • VMware 中 Ubuntu 右上角网络图标消失的 5 种终极修复方案
  • 腾讯开源OpenTenBase深度实践:企业级分布式HTAP数据库部署全攻略
  • 【URP】Unity超分辨率优化实践
  • 【yocto】Yocto Project 核心:深入了解.bbclass文件
  • 云蝠智能 Voice Agent:多语言交互时代的AI智能语音呼叫
  • 病理软件Cellprofiler使用教程
  • 【系统编程】线程控制原语
  • 半小时打造七夕传统文化网站:Qoder AI编程实战记录
  • Ansible配置文件
  • 2025第五届人工智能、自动化与高性能计算国际会议 (AIAHPC 2025)
  • YUM配置
  • 适配欧拉操作系统
  • 高频面试题:说一下线程池吧?(线程池原理,核心参数,创建方式,应用场景都要说到才能让面试官心服口服)
  • 什么是AQS?
  • Xposed框架实战指南:从原理到你的第一个模块
  • R语言使用随机森林对数据进行插补
  • 【Java基础】Java数据结构深度解析:Array、ArrayList与LinkedList的对比与实践
  • 【HarmonyOS NEXT】打包鸿蒙应用并发布到应用市场
  • 构建生产级 RAG 系统:从数据处理到智能体(Agent)的全流程深度解析
  • Linux 网络数据收发全栈工具书:从 nc、socat 到 iperf3 的 Buildroot 路径与跨平台实战
  • 开心实习之第三十二天