批量加载

使用 Redis 协议批量写入数据

批量加载是加载包含大量预先存在数据的 Redis 的过程。理想情况下,您希望快速有效地执行此作。本文档介绍了在 Redis 中批量加载数据的一些策略。

使用 Redis 协议进行批量加载

使用普通的 Redis 客户端执行批量加载不是一个好主意 有几个原因:一个接一个地发送命令的幼稚方法 速度较慢,因为您必须为每个命令的往返时间付费。 可以使用流水线,但用于批量加载许多记录 您需要在读取回复的同时编写新命令,以 确保尽快插入。

只有一小部分客户端支持非阻塞 I/O,而不是所有 客户端能够以有效的方式解析回复,以最大化 吞吐量。由于所有这些原因,将数据批量导入 Redis 是生成一个包含 Redis 协议的文本文件,原始格式, 为了调用插入所需数据所需的命令。

例如,如果我需要生成一个有数十亿个的大型数据集 的键形式为: '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 模式,要运行的命令如下所示:

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 key 值由以下协议表示:

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

或表示为带引号的字符串:

"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n"

您需要为批量加载生成的文件仅由命令组成 以上述方式表示,一个接一个。

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

def gen_redis_proto(*cmd)
    proto = ""
    proto << "*"+cmd.length.to_s+"\r\n"
    cmd.each{|arg|
        proto << "$"+arg.to_s.bytesize.to_s+"\r\n"
        proto << arg.to_s+"\r\n"
    }
    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}"))
}

我们可以直接在 pipe 中运行程序到 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

管道模式在后台的工作原理

redis-cli 的 pipe 模式内部需要的魔力是要像 netcat 一样快 并且仍然能够理解服务器发送上次回复的时间 同时。

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

  • redis-cli --pipe 尝试以最快的速度将数据发送到服务器。
  • 同时,它会在可用时读取数据,并尝试对其进行解析。
  • 一旦没有更多数据要从 stdin 读取,它会发送一个带有随机 20 字节字符串的特殊 ECHO 命令:我们确定这是最新的命令 sent,我们确信我们可以匹配回复,检查我们是否收到相同的 20 字节作为批量回复。
  • 发送此特殊的 final 命令后,接收回复的代码将开始 以匹配回复与这 20 个字节。当到达匹配的回复时 可以成功退出。

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

但是,在解析回复时,我们会对所有已解析的回复进行计数器 这样我们最后就能告诉用户命令的数量 通过批量插入会话传输到服务器。

为本页评分
返回顶部 ↑