2011-04-15 113 views
12

我使用redis以每个哈希约100k记录存储哈希。我想实现给定散列内的记录过滤(构造)。注意一个哈希条目可以属于n个过滤器。筛选Redis哈希条目

阅读thisthis之后,它看起来像我应该:

  1. 实现每一个过滤器有序集合。 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为后端。

感谢, 保罗

+0

我试图做类似的过滤器,但我有大集(1万条记录)进行过滤。你有没有找到更好的方式来过滤redis? – 2016-02-12 06:14:33

回答

4

Redis是一个无锁的非阻塞异步服务器,因此在使用流水线时不会添加争用。一收到Redis,Redis就会高兴地处理每个操作,因此实际上可以处理多个流水线操作。本质上,redis-server确实不在乎操作是否是流水线操作,它只是在接收它们时处理每个操作。

流水线的好处是减少客户端延迟,而不是在发送下一个操作之前等待来自redis-server的每个操作的响应,客户端只需一次写入即可将所有操作一次抽出,然后全部读回在一次阅读中的回应。

在这一行动的一个例子是我Redis mini StackOverflow clone每次点击使以ToQuestionResults()调用它,因为操作流水线发送1个插槽写调用的所有操作,并读取结果1插槽阻塞读这是更有效的替代每次通话读取阻塞:

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

我对使用管道值得关注的是 ,我相信它会阻止其他所有 客户在维修命令。

这不是一个值得关注的问题,我不会想到Redis是如何在这里工作的,假设它在Pipelining不阻止处理其他客户端命令的情况下效率最高。从概念上讲,你可以认为Redis的服务器进程在FIFO顺序中的每个命令(流水线与否)(即没有时间在等待/读取整个管道浪费)。

你所描述的东西更加接近其作为Redis的服务器读取EXEC(即EOF Transaction)的所有操作都在一次尽快完成MULTI/EXEC(即Redis的交易)。这不是一个问题,或者和Redis的服务器仍然没有浪费任何时间等待接收你的整个事务,它只是直到接收到最终EXEC,然后处理一次全部在排队临时队列部分命令集。

这是如何通过redis的处理每个命令,一次一个实现原子性,只要它接收它们。由于没有其他线程,所以没有线程上下文切换,没有锁定,也没有多线程问题。它通过非常快速地处理每个命令来基本实现并发性。

因此,在这种情况下,我会用流水,因为它总是一个胜利,越是这样,命令你管线(为你减少阻塞读计数)。

5

个人业务做块,但不要紧,因为他们不应该长时间运行。这听起来像你正在检索的信息比你真正需要的更多 - 当你只需要500时,HGETALL将返回100,000个项目。

发送500个HGET操作可以工作(假设集合存储散列和键)尽管有可能使用散列根本就是一个过早优化的例子 - 使用常规密钥和MGET可能会更好。

+2

谢谢你回复汤姆。你是对的,我误解了HGETALL的目的。虽然你的回答很有用,但我不会接受它,因为我不觉得它真的让我更接近原始问题。我听到你在说什么过早的优化,但似乎有序集合是实现过滤的接受的方式和哈希值存储的“对象”的最佳方式。我觉得我只是遵循最佳实践而不是做任何不寻常的事情。 – Paul 2011-04-19 09:05:59

2

我想你误会做什么流水线。当所有的命令都被发送时它不会阻塞。它所做的只是缓冲命令,然后在最后一次执行它们,这样它们就像是一个命令一样执行。在任何时候都不会发生阻塞。这同样适用于Redis的multi/exec如此。你能阻止最接近/在Redis的锁定是使用watch,这将导致exec如果Redis的密钥已经被写入,因为你叫watch失败乐观锁。

在管道块内调用hget 500次的效率更高,只需调用hmget('hash-key',*keys),其中keys是您正在查找的500个哈希键的数组。这将导致一个调用Redis的,这是一样的,如果它是流水线,但因为你不是在红宝石循环应该更快执行。