面向多企业应用的Redis键管理优化及高效删键方案问询
问题
我正在为服务数百家企业的应用搭建Redis,拟采用如下键结构:
companyname1:xxx:yyy:zzz companyname1:yyy companyname1:qqq:zz:xxx:ppp companyname1:tttt:zz:qqq companyName1:iiii:rrrr companyName1:ppp:ddd:xxx [... thousands more]
每家企业的键遵循类似模式。我需要删除仅属于companyname1且键中任意位置包含"xxx"的所有键,希望避免Redis全库搜索,请问如何对各企业的键进行分组并仅针对该分组操作?
我使用StackExchange实现了如下代码,但不确定其有效性及效率:
var keysToDelete = new List<RedisKey>(); var cursor = 0L; var pageSize = 100; // pattern = "companyName1::xxx:"; do { var redisResult = await _database.ExecuteAsync("SCAN", cursor.ToString(), "MATCH", pattern, "COUNT", pageSize).ConfigureAwait(false); var result = (RedisResult[])redisResult; cursor = Convert.ToInt64((string)result[0]); keysToDelete.AddRange((RedisKey[])result[1]); } while (cursor != 0);
专业指导
一、当前代码的核心问题
你写的pattern = "companyName1::xxx:"存在两个明显错误:
- 键的分隔符是单个冒号,但你的pattern用了两个冒号,会漏掉所有中间只有单个冒号的键;
- 该pattern只能匹配
xxx紧跟在companyName1::之后的键,无法匹配xxx在键中任意位置的场景。
二、正确的分组与过滤思路
你的键设计本身已经通过companyname1:前缀实现了企业分组,不需要额外的分组结构。要避免全库搜索,只需用精准的SCAN匹配模式,让Redis在服务器端直接过滤出目标键,而非全库扫描后在客户端过滤。
三、优化后的代码实现
直接使用StackExchange.Redis封装好的ScanAsync方法(比手动调用ExecuteAsync更简洁可靠),同时修正匹配模式、优化执行效率:
var keysToDelete = new List<RedisKey>(); long cursor = 0; // 注意Redis键大小写敏感,若需匹配companyname1和companyName1需调整模式 var scanOptions = new ScanOptions { // 匹配以companyname1开头、任意位置包含xxx的键 Match = "companyname1:*xxx*", // 调大COUNT值减少SCAN轮次,提升效率(COUNT是提示值,非精确返回数量) Count = 1000 }; do { var scanResult = await _database.ScanAsync(cursor, scanOptions).ConfigureAwait(false); cursor = scanResult.Cursor; keysToDelete.AddRange(scanResult.Items); } while (cursor != 0); // 分批删除,避免一次性删除大量键阻塞Redis const int deleteBatchSize = 1000; for (int i = 0; i < keysToDelete.Count; i += deleteBatchSize) { var batchKeys = keysToDelete.Skip(i).Take(deleteBatchSize).ToArray(); await _database.KeyDeleteAsync(batchKeys).ConfigureAwait(false); }
四、关键优化点说明
- 匹配模式修正:
companyname1:*xxx*是正确的模式,其中*是Redis通配符,代表任意长度的字符(包括空),能精准覆盖所有以companyname1:开头且包含xxx的键。 - COUNT参数调优:默认100的COUNT会增加SCAN的轮次,调至1000~5000可减少网络往返次数,提升扫描效率(Redis会根据当前数据集大小调整实际返回数量,COUNT仅为提示)。
- 分批删除:若目标键数量过万,一次性调用
KeyDeleteAsync会阻塞Redis主线程,分批删除能将性能影响降到最低。 - 大小写敏感问题:Redis键是大小写敏感的,你的示例中同时存在
companyname1和companyName1,若需同时匹配两种前缀,可使用[cC]ompany[nN]ame1:*xxx*模式,或统一键的命名规范(推荐统一小写,避免后续混乱)。
五、额外注意事项
- 尽量在业务低峰期执行删除操作,即使是渐进式SCAN和分批删除,仍会占用Redis资源;
- 若数据集极大(百万级以上键),可考虑使用Lua脚本在Redis服务器端完成扫描+删除,进一步减少网络传输开销,但需控制脚本执行时长(避免超过100ms);
- 后续维护时,可将企业前缀作为固定规范,所有针对单个企业的操作都通过前缀+通配符的方式过滤,避免全库操作。
内容的提问来源于stack exchange,提问作者Tomasz Cioch
相关产品推荐
相关产品推荐

