redis 如何高效快速批量插入大量数据到redis中

有时,Redis实例需要在很短的时间内加载大量的预先存在或用户生成的数据,以便尽可能快地创建数百万个密钥。这被称为批量插入,本文的目标是提供有关如何尽可能快地向向Redis插入大量的数据。

使用Luke协议 

使用正常模式的Redis客户端进行大容量插入是不明智的,因为一个个的插入会有大量的时间浪费在每一个命令往返时间上。 

使用管道(pipelining)还比较靠谱,但是在大量插入数据的同时又需要执行其他新命令时,这时读取数据的同时需要确保尽可能快的写入数据。

只有一小部分的客户端支持非阻塞/输出(non-blocking I/O),并且并不是所有客户端能以最大限度的提高吞吐量到高效的方式来分析答复。 

例如,如果需要生成一个10亿度keyN->valueN的大数据集,会创建一个如下的redis命令集的文件:

SET Key0 Value0
SET Key1 Value1
...
SET KeyN ValueN

一旦创建了这个文件,剩下的操作就是尽可能快地把它提交给Redis。这样做的方法在过去是使用以下命令使用netcat:

(cat data.txt; sleep 10) | nc localhost 6379 > /dev/null

但是这种批量导入并不是一个非常可靠的方法,因为netcat并不知道何时传输完所有数据,也无法检查错误。 在Redis 2.6或更高版本中,redis-cli实用程序支持一种称为pipe mode的新模式,该模式是为了执行批量插入而设计的。

使用pipe mode运行的命令如下所示:

cat data.txt | redis-cli --pipe

这将产生一个类似于这样的输出:

All data transferred. Waiting for the last reply...
Last reply received from server.
errors: 0, replies: 1000000

redis-cli实用程序还确保只从Redis实例收到的错误重定向到标准输出。

生成Redis协议

Redis协议生成和解析极其简单,并在此处进行记录。 然而,但是为了生成大量数据插入的目标,就需要了解每一个细节协议,每个命令都以下列方式表示:

*<args><cr><lf>
$<len><cr><lf>
<arg0><cr><lf>
<arg1><cr><lf>
...
<argN><cr><lf>

其中<cr>表示“\ r”(或ASCII字符13),<lf>表示“\ n”(或ASCII字符10)。

例如,命令SET键值由以下协议表示:

*3<cr><lf>
$3<cr><lf>
SET<cr><lf>
$3<cr><lf>
key<cr><lf>
$5<cr><lf>
value<cr><lf>

或者用引用的字符串表示:

"*3\r$3\rSET\r$3\rkey\r$5\rvalue\r"

您需要为批量插入生成的文件只是由以上述方式表示的命令组成,一个接一个地。

以下Ruby函数生成有效的协议:

def gen_redis_proto(*cmd)
    proto = ""
    proto << "*"+cmd.length.to_s+"\r"
    cmd.each{|arg|
        proto << "$"+arg.to_s.bytesize.to_s+"\r"
        proto << arg.to_s+"\r"
    }
    proto
end

puts gen_redis_proto("SET","mykey","Hello World!").inspect

使用上面的函数,可以很容易地在上面的例子中用这个程序生成键值对:

(0...1000).each{|n|
    STDOUT.write(gen_redis_proto("SET","Key#{n}","Value#{n}"))
}

我们可以直接运行程序到redis-cli来执行我们的第一个批量导入会话。

$ ruby proto.rb | redis-cli --pipe
All data transferred. Waiting for the last reply...
Last reply received from server.
errors: 0, replies: 1000

pipe mode的工作原理?

难点是保证redis-cli在pipe mode模式下执行和netcat一样快的同时,如何能理解服务器发送的最后一个回复。

这是通过以下方式获得的:

  • redis-cli --pipe尝试尽可能快地将数据发送到服务器。

  • 读取数据时同时,解析它。

  • 一旦没有更多的数据输入,它就会发送一个特殊的echo命令,后面跟着20个随机的字符。我们相信可以通过匹配回复相同的20个字符是同一个命令的行为。

  • 一旦发送了这个特殊的最终命令,接收到回复的代码就开始匹配这20个字节的回复。当匹配时,它可以成功退出。

使用这个技巧,我们不需要解析我们发送到服务器的协议,以了解我们发送了多少个命令,而只是回复。

然而,在解析答复时,我们将所有解析的答案都计数在一个计数器上,以便在最后我们能够通过质量插入会话告诉用户传送给服务器的命令的数量。

原文:https://redis.io/topics/mass-insert

相关文章:

Redis RDB方式数据备份与恢复

redis 持久化详解,RDB和AOF是什么?他们优缺点是什么?运行流程是什么?

redis 如何高效快速批量插入大量数据到redis中

Redis 列表详解

Redis 字符串详解

Redis 5种数据结构简介和对应的命令及代码示例


相关文章

文章浏览阅读1.3k次。在 Redis 中,键(Keys)是非常重要的概...
文章浏览阅读3.3k次,点赞44次,收藏88次。本篇是对单节点的...
文章浏览阅读8.4k次,点赞8次,收藏18次。Spring Boot 整合R...
文章浏览阅读978次,点赞25次,收藏21次。在Centos上安装Red...
文章浏览阅读1.2k次,点赞21次,收藏22次。Docker-Compose部...
文章浏览阅读2.2k次,点赞59次,收藏38次。合理的JedisPool资...