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規範協議的問題。
天下國家,可均也;爵祿,可辭也;白刃,可蹈也;中庸不可能也