这是一个跟进问题Segmenting Redis By Database。 我最初询问一个redis实例中不同数据库中redis 键操作的时间复杂度。我问的原因是因为我试图实现一个缓存,其中有 x 多段密钥,每个密钥都可能有 y < / em> 实际数据实例,导致 xy 总密钥。
但是,我想支持主键的通配符搜索,似乎在redis中唯一实现的密钥的通配符查询是 keys 命令,其使用气馁。在我看来,将 x 键放在一个单独的数据库中是一个不错的折衷方案,其中较少数量的键将使键操作表现令人满意。
有人可以提出更好的选择吗?
感谢。
答案 0 :(得分:4)
我仍然认为使用KEYS实际上无法通过Redis进行扩展,无论您采用何种聪明的方案来处理线性复杂性。
分区是这种方案之一,它通常用于传统的RDBMS中,以降低平台上表扫描的成本。你的想法实际上是对Redis这个概念的改编。
但与提供此功能的传统RDBMS(Oracle,MySQL,...)相比,有一个重要的区别:Redis是一个单线程事件循环。因此,扫描不能与任何其他活动同时进行(例如,提供其他客户端连接)。当Redis扫描数据时,它将被阻止所有连接。
您必须设置大量分区(即数据库)才能获得良好的性能。类似全球键数的1/1000或1/10000。这就是它不可扩展的原因:Redis不是为处理这么多数据库而设计的。您可能会遇到内部机制迭代所有数据库的问题。这是从源代码中提取的列表:
您可能必须限制数据库的数量,这也限制了可伸缩性。如果设置1000个数据库,那么对于1M项目来说它将正常工作,对于10M项目将会更慢,而对于100M项目则无法使用。
如果您仍然希望坚持使用线性扫描来实现此功能,那么支持并发扫描的其他商店(如MySQL,MongoDB等)将为您提供更好的服务。对于其他商店,关键点是以有效的方式实现商品到期。
如果您真的必须使用Redis,则可以轻松地对数据进行分段,而无需依赖多个数据库。例如,您可以使用我所描述的方法here。使用此策略,将以增量方式检索密钥列表,并且搜索实际上是在客户端完成的。主要的好处是你可以拥有大量的分区,因此Redis不会阻止。
现在,AFAIK没有存储引擎提供了使用任意正则表达式有效搜索数据的能力(即避免线性扫描)。但是,此功能由一些搜索引擎提供,通常使用n-gram索引。
以下是来自Russ Cox的一篇很好的文章:http://swtch.com/~rsc/regexp/regexp4.html
这种索引机制可能适用于Redis(您可以使用Redis来存储密钥的三元组索引),但它代表了很多要编写的代码。
您还可以设想将正则表达式限制为前缀搜索。例如U:SMITH :(。*)实际上是一个前缀为U的搜索:SMITH:
在这种情况下,您可以使用zset索引键,并在检索到您感兴趣的键范围后在客户端执行线性搜索。 zset中项目的得分是根据客户端的键计算得出的,因此得分顺序对应于键的词典顺序。
使用这样的zset,可以通过zscore和zrange命令的组合来检索必须通过块扫描块的键的范围。结果是扫描的密钥数量受到限制(通过前缀),搜索发生在客户端,并且它与Redis并发模型是友好的。缺点是复杂性(特别是处理项目到期)和网络带宽消耗。