在Redis中获取O(1)时间复杂度的最后20个哈希项?

时间:2014-06-05 10:28:10

标签: hash redis

遵循Redis的建议,我必须尽可能使用哈希:

  

小哈希在非常小的空间中编码,所以你应该尝试   每次可能使用哈希表示您的数据。对于   实例,如果您有在Web应用程序中表示用户的对象,   而不是使用不同的名称,姓氏,电子邮件,密码,   使用包含所有必填字段的单个哈希。

并且我将有数百万件物品,我试图将帖子存储为哈希:

hmset post:1 title "hello"

hmset post:2 title "hi"

hmset post:3 title "g'day"

现在,我知道我可以像创建它一样简单地检索哈希:

hgetall post:1

问题在于我想要检索多个,可能在一行中检索20个。

我尝试了以下没有工作的命令(当然没有3个点):

hgetall post:1 post:2 post:3 post:4...

发出以下错误:

(error) ERR wrong number of arguments for 'hgetall' command

我可以做这个客户端:

hgetall post:1

然后

hgetall post:2

依此类推..但这将是巨大的浪费网络资源和潜在的性能瓶颈,因为系统应该能够平均同时处理至少5000个用户/秒。

我做错了,完成此任务的最佳方法是什么?有没有办法发送这个命令一次而不是顺序执行?是否有可以在哈希上进行的 lrange 类型的操作?

2 个答案:

答案 0 :(得分:1)

你正朝着正确的方向前进 - 为20个帖子中的每个帖子一个接一个地做你的HGETALL。但是,为了节省网络往返次数,请考虑使用Redis的流水线技术,它基本上允许您对请求进行分组/批处理。或者,您可以通过实现自己的HGETALL版本来实现类似的结果,该版本接受带有服务器端Lua脚本的多个密钥名称。

答案 1 :(得分:1)

正如您所指出的那样,您可以使用 Pipelined 请求一次发送多个命令。

来自the Redis page dedicated to Pipelining

  

可以实现请求/响应服务器以便它能够   即使客户端尚未阅读旧请求,也会处理新请求   响应。这样就可以发送多个命令   服务器根本没有等待回复,最后阅读了   只需一步即可回复。

     

这称为流水线技术,是一种广泛使用的技术   几十年。例如,已经有许多POP3协议实现   支持此功能,大大加快了这一过程   从服务器下载新电子邮件。

如果我没有错,那就是 HMSET 命令使用的技术," Pipelines"多个 HSET 命令。

Redis网站的一个片段显示了一个使用Ruby进行管道传输的示例:

require 'rubygems'
require 'redis'

def bench(descr)
    start = Time.now
    yield
    puts "#{descr} #{Time.now-start} seconds"
end

def without_pipelining
    r = Redis.new
    10000.times {
        r.ping
    }
end

def with_pipelining
    r = Redis.new
    r.pipelined {
        10000.times {
            r.ping
        }
    }
end

bench("without pipelining") {
    without_pipelining
}
bench("with pipelining") {
    with_pipelining
}
Go还有一个名为Redigo的客户端,能够命令管道传输:

// Initialize Redis (Redigo) client on port 6379 
//  and default address 127.0.0.1/localhost
client, err := redis.Dial("tcp", ":6379")
  if err != nil {
  panic(err)
}
defer client.Close()

// Initialize Pipeline
client.Send("MULTI")

// Send writes the command to the connection's output buffer
client.Send("HGETALL", "post:1") // Where "post:1" contains " title 'hello' content 'hi' "

client.Send("HGETALL", "post:2") // Where "post:1" contains " title 'g'day' content 'g'mornin' "

// Execute the Pipeline
pipe_prox, err := client.Do("EXEC")

if err != nil {
  panic(err)
}

log.Println(pipe_prox)

这很好,只要您能够轻松显示非字符串结果..我仍然在尝试找到将结果转换为字符串的方法,截至目前我已经得到了这个:

[[[116 105 116 108 101] [104 105]] [[116 105 116 108 101] [104 101 108 108 111]]]

执行以下操作不会有任何帮助:

result, _ := redis.Strings(pipe_prox, err)

log.Println(pipe_prox)

这就是我得到的:

[]

我会在设法解决此问题后立即更新此答案。