过滤 Redis 哈希表条目

13
我正在使用redis存储每个散列中约100k条记录。我想要在给定的散列内实现筛选(分面)。请注意,一个散列条目可以属于n个过滤器。
阅读thisthis后,看起来我应该:
  1. 每个过滤器实现一个排序的SET。 SET中的值对应于HASH中的键。
  2. 从给定的过滤器SET中检索HASH键。
  3. 一旦我从SET中获取了HASH键,就从HASH中获取相应的条目。这将为我提供所有属于过滤器的条目。
首先,上述方法在高层次上是否正确?
假设方法是正确的,我缺少的部分是什么是检索HASH条目的最有效实现方式?我是否正确地认为,一旦我拥有了HASH键,我应该使用PIPELINE来排队多个HGETALL命令通过每个HASH键?是否有更好的方法?
我对使用PIPELINE的担忧是,我认为它会在服务命令时阻止所有其他客户端。我将使用每页500个结果进行分页筛选,有多个基于浏览器的客户端执行过滤操作,更不用说填充SET和HASH的后端进程,如果PIPELINE会阻塞,那么存在很大的竞争潜力。是否有人可以提供一些看法?
如果有帮助的话,我正在使用2.2.4 redis,predis用于Web客户端,servicestack用于后端。
谢谢, 保罗

我正在尝试做类似的过滤器,但是我有大量数据(100万条记录)需要过滤。你有没有在Redis中找到更好的过滤方法? - devendra tata
3个回答

5
Redis是一个无锁非阻塞异步服务器,因此在使用流水线时不会增加争用。Redis愉快地处理每个操作,因此实际上可以处理多个流水线操作。实质上,redis-server并不关心操作是否被流水线化,它只是在收到每个操作时处理它们。
流水线的好处是减少客户端的延迟,其中客户端可以一次性将所有操作泵送到单个写入中,而不是等待每个操作的redis-server响应后再发送下一个操作,并在单个读取中读回所有响应。
这在我的Redis mini StackOverflow clone中有一个示例,每次点击都会调用ToQuestionResults(),因为操作已经流水线化,所以可以在一个Socket写入调用中发送所有操作,并在一个Socket阻塞读取中读取结果,这比每个调用的阻塞读取更有效率。

https://github.com/ServiceStack/ServiceStack.Examples/blob/master/src/RedisStackOverflow/RedisStackOverflow.ServiceInterface/IRepository.cs#L180

我的担忧是使用管道会阻塞其他客户端的服务,但这不是一个有效的担忧。Redis会以最高效的方式处理管道,不会阻塞其他客户端命令的处理。从概念上讲,redis-server按照FIFO顺序处理每个命令(包括管道和非管道命令),不会浪费时间在等待/读取整个管道上。您描述的更接近于MULTI/EXEC(即Redis事务),其中所有操作在Redis服务器读取EXEC(即EOF事务)时立即完成。这也不是问题,Redis服务器只需将部分命令集排队到临时队列中,直到接收到最终的EXEC,然后一次性处理它们。这就是Redis通过尽快处理每个命令来实现原子性的方式。由于没有其他线程,因此不存在线程上下文切换、锁定和多线程问题。基本上,它通过快速处理每个命令来实现并发处理。
因此,在这种情况下,我会使用管道处理,因为它总是胜利的,尤其是当您将更多命令进行管道处理时(因为您减少了阻塞读取计数)。

5

单个操作会阻塞,但是这并不重要,因为它们不应该运行很长时间。听起来你正在检索比实际需要的更多的信息 - 当你只需要500个时,HGETALL将返回100,000个条目。

发送500个HGET操作可能会起作用(假设集合存储了哈希和键),尽管使用哈希可能是过早优化的情况 - 你最好使用常规键和MGET。


2
谢谢回复,汤姆。你说得对,我误解了HGETALL的目的。虽然你的答案很有用,但我不会接受它,因为我觉得它并没有让我更接近原始问题。我听到你关于过早优化的说法,但似乎有序集是实现过滤的可接受方式,而哈希则是存储“对象”的最佳方式。我觉得我只是在遵循最佳实践,而不是做任何不寻常的事情。 - Paul

2
我认为你误解了流水线的作用。它不会在所有命令被发送时阻塞。它所做的只是缓冲这些命令,然后在最后一次性执行它们,使它们像一个单独的命令一样被执行。没有任何阻塞发生。Redis的multi/exec也是如此。在Redis中最接近阻塞/锁定的是使用watch进行乐观锁定,如果自从调用watch以来Redis键已被写入,则会导致exec失败。
更有效率的方法是在管道块内部调用hget 500次,而是只需调用hmget('hash-key',*keys),其中keys是您要查找的500个哈希键的数组。这将导致对Redis的单个调用,这与流水线相同,但应该更快地执行,因为您不会在Ruby中循环。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接