通过通配符模式高效地批量删除RedisKeys

9gm1akwq  于 2022-12-03  发布在  Redis
关注(0)|答案(1)|浏览(317)

问题:我需要使用通配符模式高效地从Redis缓存中删除键。最终一致性是可接受的。
技术堆栈

  • .NET 6(全程异步)
  • 堆栈交换.Redis 2.6.66
  • Redis服务器6.2.6
  • 我目前在Redis中有大约50万个密钥。
  • 由于各种原因,我无法使用RedisJSON
    示例:我用键存储了以下3个STRING类型:
dailynote:getitemsforuser:region:sw:user:123
dailynote:getitemsforuser:region:fl:user:123
dailynote:getitemsforuser:region:sw:user:456
...

其中每个STRING存储JSON的方式如下:

> dump dailynote:getitemsforuser:region:fl:user:123
"{\"Name\":\"john\",\"Age\":22}"

最初的解决方案使用KeysAsync方法通过通配符模式来检索要删除的键列表。由于Redis服务器是6.x,SCAN功能被KeysAsync内部的StackExchange.Redis nuget使用。
最初的实现使用了通配符模式dailynote:getitemsforuser:region:*。正如人们所预料的那样,这个解决方案没有很好地扩展,我们开始看到RedisTimeoutExceptions
我知道“尽可能避免在PROD中出现这种情况”,也看到Marc Gravell在SO和StackExchange上回答了其他一些问题。Redis GitHub。我能想到的唯一可能的替代方法是使用Redis SET来“跟踪”每个RedisKey,然后从SET中检索值列表(这是我需要删除的键)。然后删除SET以及返回的键。

潜在解决方案?

1.创建一个Redis SET,其键为dailynote:getitemsforuser,其值为dailynote:getitemsforuser:region:XX...形式的键
SET看起来如下所示:

dailynote:getitemsforuser (KEY)
    dailynote:getitemsforuser:region:sw:user:123 (VALUE)
    dailynote:getitemsforuser:region:fl:user:123 (VALUE)
    dailynote:getitemsforuser:region:sw:user:456 (VALUE)
    ...

我仍然会有每个单独的STRING类型:

dailynote:getitemsforuser:region:sw:user:123
dailynote:getitemsforuser:region:fl:user:123
dailynote:getitemsforuser:region:sw:user:456
...

1.当需要执行“通配符”删除时,我获取dailynote:getitemsforuserSET的成员,然后调用RemoveAsync,将集合的成员传递为RedisKey[]。然后使用SETdailynote:getitemsforuser)的密钥调用RemoveAsync
我正在寻找关于解决方案可行性的反馈、替代想法、陷阱和改进建议。TIA

kpbwa7wx

kpbwa7wx1#

REDIS的KEYS和SCAN的最大问题是,它们需要对存储每个Redis密钥的庞大哈希表进行全面扫描。即使你使用了模式,它仍然需要 * 检查 * 哈希表中的每一个条目,看看它是否匹配。
假设你在设置键中的值的同时调用SADD--这样就避免了调用SCAN--这应该是可行的。值得注意的是,如果Set很大,调用SMEMBERS来获取Set的所有成员也会导致问题。Redis是单线程的--在返回所有成员时会阻塞。你可以通过使用SSCAN来缓解这个问题。StackExchange.Redis可能已经做到了。I“我不能肯定。
你也可以写一个Lua脚本来读取Set并原子地UNLINK所有的键,这样可以减少网络,但如果花费太长的时间,可能会束缚Redis。

相关问题