1、介绍
有时候,Redis实例须要在很短的时间内加载大量先前存在或用户生成的数据,以便尽量快地建立数百万个键。这就是所谓的批量插入,本文档的目标是提供有关如何以尽量快的速度向Redis提供数据的信息。若是想查看英文原文,地址以下:https://redis.io/topics/mass-insert
2、操做详解
linux
话很少说,直接进入主题了。
一、使用协议,卢克(Use the protocol, Luke)
使用普通Redis客户端的方式执行批量插入的操做并非一个很好的办法,缘由以下:发送一个命令的方式很慢,由于您必须为每一个命令都会有往返的时间消耗。虽然可使用管道模式来操做,但为了批量插入多条记录,您须要在读取回复的同时编写新命令,以确保尽量快地插入。
另外,只有一小部分客户端支持非阻塞 I/O 操做,并且并非全部的客户端都可以以最大化吞吐量这种有效的方式来解析这些回复。 因为以上这些缘由,将大量数据导入Redis的首选方式是生成包含Redis协议的文本文件(原始格式),以便调用插入所需数据所需的命令。
例如,若是我须要生成一个大型数据集,其中包含数十亿个键:“keyN - > ValueN”,我将建立一个包含以下Redis协议格式的命令的文件:redis
SET Key0 Value0 SET Key1 Value1 ... SET KeyN ValueN
一旦建立了该文件,剩下的操做就是尽量快地将其提供给Redis。在过去,作法是使用以下的netcat的命令:ruby
(cat data.txt; sleep 10) | nc localhost 6379 > /dev/null
然而,这并非一个很是可靠的方式来执行批量导入,由于 netcat 命令并不会真正知道全部数据什么时候传输完毕,而且也没法检查发生的错误。在Redis的2.6或更高版本中,redis-cli实用程序支持称为管道的新模式,该模式就是为了执行批量插入而存在的。
使用管道模式,运行的命令以下所示:服务器
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协议(Generating Redis Protocol)
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 value 由如下协议表示:unix
*3<cr><lf> $3<cr><lf> SET<cr><lf> $3<cr><lf> key<cr><lf> $5<cr><lf> value<cr><lf>
或者表示为引用的字符串:orm
"*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n"
为批量插入而生成的文件只不过是由以上述方式表示的一个接一个的命令组成的。
如下Ruby函数生成有效的协议:server
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}")) }
咱们能够在redis-cli的管道中直接运行程序,以执行咱们的第一次海量导入会话。
$ ruby proto.rb | redis-cli -h 192.168.127.130 -p 6379 --pipe All data transferred. Waiting for the last reply... Last reply received from server. errors: 0, replies: 1000
三、管道模式如何在引擎下工做(How the pipe mode works under the hoods)
redis-cli管道模式的速度和netcat同样快,与此同时,仍然可以明白服务器最后一次发送回复的时间。
这是经过如下方式得到的:
3.一、redis-cli --pipe Redis客户端会尽量快的向服务器发送数据。
3.二、同时,会尽量快的读取并解析数据文件中的内容。
3.三、一旦从标准输入设备读取数据完毕,它将会发送一个带有20个字节的字符串的特殊的ECHO命令到服务器:咱们确信这是最新发送的命令,若是咱们收到做为批量回复的相同的20个字节的消息,咱们确信能够作“答复匹配检查”。
3.四、这个特殊的最终命令一经发送,Redis服务器端将接收到回复和这20个字节的回复消息作匹配。若是匹配,它能够成功退出,表示插入完毕。
使用这个技巧,咱们不须要解析咱们发送给服务器的协议,以了解咱们发送了多少条命令,仅仅是一个答复而已。
可是,在解析回复时,咱们会对全部解析的回复进行计数,以便在最后咱们可以告诉用户传输到服务器的命令的数量在此次批量插入的会话中。
四、示例代码操做
4.一、准备数据文件,格式是文本文件,名称是:redis_commands.txt。
我在Windows环境下生成了一个txt文件,一条数据一行,代码以下:
SET Key0 Value0 SET Key1 Value1 SET Key2 Value2 SET Key3 Value3 SET Key4 Value4 SET Key5 Value5 SET Key6 Value6 SET Key7 Value7 SET Key8 Value8 SET Key9 Value9 SET Key10 Value10 ... SET KeyN ValueN
我生成了500万的数据,由于这个文本文件我是在Windows环境下生成的,因此须要格式转换。
4.二、若是使用Windows环境下生成的文件,须要进行格式转换,若是是在Linux环境下生成的文件就不须要格式转换,若是文本文件比较大,执行转换时间会有几秒,等待便可。
执行格式转换
[root@linux ~]# unix2dos redis_commands.txt unix2dos:converting file redis_commands.txt to DOS format ...
以上代码进行格式转换完毕
须要说明一点,unix2dos这个命令须要先安装,若是没有安装,会提示:command not found。
执行如下命令安装:
[root@linux ~]# yum install unix2dos
4.三、进行数据批量插入
[root@linux ~]# cat redis_commands.txt | redis-cli -h 192.168.127.130 -p 6379 [-a "password"] -n 0 --pipe All data transferred.Waiting for the last reply... Last reply received from server. errors:0,replies:10000000
批量插入数据成功,一千万的数据大概要花费50几秒左右。
3、总结
好的,今天就写到这里,大批量数据插入的就是这么容易。只要理解了,其实也不是很难,技术就是一层窗户纸,一捅就破,可是没人捅就比较麻烦。下一篇文章,咱们将写一些关于redis协议格式的文章,若是要涉及大批量数据插入,就会涉及到redis规范协议的问题。
天下国家,可均也;爵禄,可辞也;白刃,可蹈也;中庸不可能也