域名站长工具,苏州专业做网站公司电话,网站建设公司工资标准,医院建设网站的作用序言
网上看到的面试题#xff1a;Redis有1亿个key#xff0c;其中10w个key是以某个固定的前缀开头#xff0c;如何将它们全部找出来#xff1f;一般有两种命令可以实现#xff1a;
Keys命令Scan命令
下面具体分析一下两种命令
Keys命令
Keys pattern如下图所示…序言
网上看到的面试题Redis有1亿个key其中10w个key是以某个固定的前缀开头如何将它们全部找出来一般有两种命令可以实现
Keys命令Scan命令
下面具体分析一下两种命令
Keys命令
Keys pattern如下图所示建了一些不同数据结构String、Hash、List、Set、ZSet的Key使用命令找出前缀为prefix的Keykey区分大小写
时间复杂度On笔记本电脑40毫秒内可以查100w个键值对生产环境慎用大型数据库上执行会影响性能
那么在大型数据库场景下为什么不能使用该命令呢
Keys命令是一个阻塞式操作。
单线程模型Redis的命令处理是基于单线程的。一个命令在执行时其他所有客户端的请求都必须等待全量遍历Keys为了找出所有匹配的key会遍历数据库NoSQL中所有的key遍历完成之前Redis无法处理任何其他命令。生产环境灾难如果正在有1亿个key的实例上执行Keys命令会导致Redis服务卡顿数十秒甚至数分钟所有依赖Redis的业务都会出现超时和雪崩会导致严重的生产事故。
Scan命令
SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]单次调用时间复杂度O1完整迭代时间复杂度On所以单次调用不会长时间阻塞线上服务非阻塞式渐进式迭代该命令允许增量迭代每次调用返回少量数据然后返回一个游标cursor下次传入这个游标Redis就会接着上次结束的地方继续扫描如上图scan xxx match prefix* count 3每次返回的游标不一定按照顺序COUNT参数COUNT是一个建议值告诉Redis希望每次迭代返回大约多少个key。但不是精确的有时多有时少但是可以控制单次扫描的粒度。如上图scan xxx match prefix* count 3每次返回的数据量不一定都是3
参看官网相关的还有其他的一些扫描指令
SSCANiterates elements of Sets types.针对Set数据结构HSCANiterates fields of Hash types and their associated values.针对Hash数据结构ZSCANiterates elements of Sorted Set types and their associated scores.针对ZSet数据结构 实际操作
实际项目中可能会通过python脚本或者LUA脚本去执行查找下面是使用python代码去执行的示例代码
import redisr redis.Redis(hostlocalhost, port6379)
cursor 0
prefix your_prefix:*
found_keys []while True:cursor, keys r.scan(cursor, matchprefix, count10000)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的所有成员这样时间复杂度即使是On遍历的也是10w数据而非NoSQL数据库中的1亿条数据删除时除了删除原始key还需要从索引Set中移除对应的成员
从节点Replica执行
假设这是一个低频且用于离线分析的需求并且不想修改现有的数据结构可以考虑在Redis集群主从、哨兵、集群模式的从节点去执行SCAN命令操作甚至Keys命令避免长时间耗时影响主节点Master的正常读写。