13

我正在使用 redis 存储每个散列约 100k 记录的散列。我想在给定的哈希中实现过滤(分面)记录。请注意,一个哈希条目可以属于 n 个过滤器。

在阅读了这个这个之后,我看起来应该:

  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,用于 Web 客户端的 predis 和用于后端的 servicestack。

谢谢,保罗

4

3 回答 3

5

个别操作确实会阻塞,但这并不重要,因为它们不应该长时间运行。听起来您检索的信息比您真正需要的信息多 - 当您只需要 500 项时,HGETALL 将返回 100,000 项。

发送 500 个 HGET 操作可能会起作用(假设集合同时存储了散列和键),尽管使用散列可能是过早优化的一种情况 - 使用常规键和 MGET 可能会更好。

于 2011-04-18T05:35:38.747 回答
5

Redis 是一个无锁的非阻塞异步服务器,因此在使用流水线时不会增加争用。Redis 在收到每个操作后就会愉快地处理它们,因此在实践中可以处理多个流水线操作。本质上,redis-server 并不关心操作是否流水线化,它只是在接收到每个操作时对其进行处理。

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

这方面的一个例子是在我的Redis 迷你 StackOverflow 克隆中,每次单击都会调用ToQuestionResults()它,因为操作是流水线的,因此会在 1 个 Socket 写入调用上发送所有操作,并在 1 个 Socket 阻塞读取中读取结果,这比阻塞更有效每次通话阅读:

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

我对使用 PIPELINE 的担忧是我相信它会在为命令提供服务时阻止所有其他客户端。

这不是一个有效的问题,我不会过多地考虑 Redis 在这里是如何工作的,假设它在流水线不阻止其他客户端命令的处理的情况下最有效地做到这一点。从概念上讲,您可以认为 redis-server 以 FIFO 顺序处理每个命令(流水线或非流水线)(即不会浪费时间等待/读取整个流水线)。

您正在描述更接近 MULTI/EXEC(即 Redis 事务)的东西,其中所有操作在 Redis 服务器读取 EXEC(即 EOF 事务)后立即完成。这也不是问题,redis-server 仍然不会浪费任何时间等待接收您的整个事务,它只是将部分命令集排队在一个临时队列中,直到它收到最终的 EXEC,然后一次处理所有这些。

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

所以在这种情况下,我会使用流水线,因为它总是一个胜利,所以你流水线的命令越多(因为你减少了阻塞读取计数)。

于 2011-05-05T02:34:29.190 回答
2

我认为您误解了流水线的作用。在发送所有命令时它不会阻塞。它所做的只是缓冲命令,然后在最后一次执行它们,因此它们被执行就好像它们是一个单一的命令一样。任何时候都不会发生阻塞。multiredis /也是如此exec。在 redis 中最接近阻塞/锁定的方法是使用 乐观锁定,如果自调用以来已写入 redis 密钥watch,这将导致失败。execwatch

比在管道块中调用 500 次更有效hget的是只调用hmget('hash-key',*keys)wherekeys是您正在查找的 500 个哈希键的数组。这将导致对 redis 的一次调用,这与它是流水线的一样,但执行起来应该更快,因为你没有在 ruby​​ 中循环。

于 2011-06-14T22:32:18.813 回答