假设我们现在有一个需求,需要往redis中添加1000完条数据。注意这1000万数据是没有重复的,因此我们只需要把这1000万数据添加到redis中的一个集合中。
命令行添加方式如下:
SADD [集合名称] 成员1,成员2,...
例如
SADD FRUIT apple banana pear
这样添加的效率低,时间都耗费了网络传输和命令传输的往返时间上,如果添加的数据量不多还好,如果添加的数据达到百万甚至千万级,这样在添加的过程中耗费了大量的时间。那么redis是如何在很短的时间内加载已生成的大量数据的呢?在2.6或更高版本的Redis中,该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协议
Redis协议生成和解析非常简单,并 在此处记录。但是,为了生成大规模插入目标的协议,您不需要了解协议的每个细节,而只需要按以下方式表示每个命令:
*3\r\n 命令起始,定义共3个输入参数
$3\r\n 下一个参数字节长度
SET\r\n 命令参数
$3\r\n 下一个参数字节长度
key\r\n 变量参数
$5\r\n 下一个参数字节长度
value\r\n 值参数
注意:此处的\r\n为换行符,不是输入的字符。在这里我耗了很长的时间。。。。英文不好没办法。
下面是一个例子
*3
$4
SADD
$18
USER_UID_LIST_TEST
$6
111111
假设我们又一个文本中都是存着上述格式的文本,我们可以通过命令行这样执行:
cat user_uid.txt | redis-cli -h 127.0.0.1 --pipe
go 语言实现
对于redis-pipe,go-redis库实现了该功能,代码如下
package main
import (
"fmt"
"github.com/go-redis/redis"
)
func main() {
/* client := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{"127.0.0.1:6379"},
ReadOnly: true,
RouteRandomly: true,
})
*/
client := redis.NewClient(&redis.Options{
Addr: "127.0.0.1:6379",
Password: "",
})
pipe := client.Pipeline()
pipe.SAdd("USER_UID_LIST_TEST", "123")
pipe.SAdd("USER_UID_LIST_TEST", "456")
cmders, err := pipe.Exec()
if err != nil {
fmt.Println("err", err)
}
for _, cmder := range cmders {
//cmd := cmder.(*redis.StringStringMapCmd)
cmd := cmder.(*redis.IntCmd)
res, err := cmd.Result()
if err != nil {
fmt.Println("err", err)
}
fmt.Println("res", res)
}
}