问题:我需要使用通配符模式高效地从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:getitemsforuser
SET
的成员,然后调用RemoveAsync
,将集合的成员传递为RedisKey[]
。然后使用SET
(dailynote:getitemsforuser
)的密钥调用RemoveAsync
我正在寻找关于解决方案可行性的反馈、替代想法、陷阱和改进建议。TIA
1条答案
按热度按时间kpbwa7wx1#
REDIS的KEYS和SCAN的最大问题是,它们需要对存储每个Redis密钥的庞大哈希表进行全面扫描。即使你使用了模式,它仍然需要 * 检查 * 哈希表中的每一个条目,看看它是否匹配。
假设你在设置键中的值的同时调用SADD--这样就避免了调用SCAN--这应该是可行的。值得注意的是,如果Set很大,调用SMEMBERS来获取Set的所有成员也会导致问题。Redis是单线程的--在返回所有成员时会阻塞。你可以通过使用SSCAN来缓解这个问题。StackExchange.Redis可能已经做到了。I“我不能肯定。
你也可以写一个Lua脚本来读取Set并原子地UNLINK所有的键,这样可以减少网络,但如果花费太长的时间,可能会束缚Redis。