Redis | 管道 —— PipeLine

在我们使用 Redis 的时候,通常是使用一条一条的命令来进行操作,比如我们可以执行一个 “set key1 value1” 这样的操作,然后再执行一个 "set key2 value" 这样的操作。Redis 是基于客户端和服务端的模式,当客户端和服务端进行通信的时候,通常会使用 Socket 来进行网络的通信。当我们执行 "set key value" 时,客户端会对服务器发送一个数据包,当我们再次执行 "set key2 value2" 时,客户端又会对服务器发送一个数据包。这样,看起来没有什么太多的问题,但是当数据量过大的时候,这样的发送会产生一定的网络延时,如果通过 Wireshark 一类的软件抓包的话,可以看到每次执行命令时,都会发送一个 PSH 包和一个 ACK 的包。为了在大量数据写入 Redis 时可以降低时延,Redis 引入了管道。

管道

管道时非常常用的技术,而且由来已久。在 Redis 中的 管道 是一种一次发送多个命令的功能,这样可以节省数据往返的时间。

Redis 的管道,在 Linux 下可以使用 echo 和 nc 命令来进行测试,在 Windows 下可以使用 type 和 nc 命令来进行测试。无论在 Linux 下,还是 Windows 下,nc 都需要单独进行安装。

我们先来使用 nc 进行测试,nc 是一个网络工具,它被号称为 瑞士军刀。我最早在 2002 年时就已经听说过它,至今 nc 都一直被使用在网络测试、网络安全等方面。

我们先来安装 nc 这个工具,安装方式很简单,即

yum install nc -y

复制

安装完 nc 以后,我们来查看 Redis 服务器中的数据,命令如下:

[root@VM_0_4_centos ~]# redis-cli
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> exit

复制

可以看出,Redis 服务器中没有任何的数据,然后我们使用 nc 来向 Redis 服务器进行数据的发送,命令如下:

[root@VM_0_4_centos ~]# nc localhost 6379
keys *
*0
set k1 v1   
+OK

复制

当我们输入命令 “nc localhos 6379” 后,nc 处于等待输入的状态,我输入了 “keys *” 这条命令后按下回车,命令行中回显了 “*0”,当我再次输入 “set k1 v1” 命令后,命令行中回显了 “+OK”。

输入完上面的命令之后,按下 Ctrl + C ,返回到 Linux 的命令行下,通过 redis-cli 来查看 Redis 服务器中的数据,命令如下:

[root@VM_0_4_centos ~]# redis-cli
127.0.0.1:6379> keys *
1) "k1"
127.0.0.1:6379> get k1
"v1"

复制

可以看到,Redis 服务器中已经存在了 k1 这个键。

虽然,我们执行了 Redis 的命令,但是并没有批量的执行命令,那么我们接着测试,测试之前先清除掉 Redis 中的数据,并在命令执行如下命令。

[root@VM_0_4_centos ~]# echo -e "set k1000 1000\n incr k1000\n get k1000\n" | nc localhost 6379
+OK
:1001
$4
1001
[root@VM_0_4_centos ~]# redis-cli
127.0.0.1:6379> keys *
1) "k1000"
127.0.0.1:6379> get k1000
"1001"

复制

echo -e 是将字符串中的 "\" 后面的字符作为转移符,\n 换行。这样,通过 echo 将输出给到 nc,nc 将字符串批量的写入到了 Redis 中。

Redis的管道参数

虽然 nc 能帮助我们完成批量的写入,但是,每次想要批量的导入数据都要使用 nc 这个命令貌似很奇怪,不过不要紧,Redis 也提供了相关的管道参数 --pipe。

我们准备一个文件,该文件名为 cmd.txt,文件中保存一些 Redis 的命令,文本如下:

set k100 v100
set k200 v200
hset k300 name haha
hset k300 age 20
hset k300 gender male

复制

然后,清除 Redis 中的数据,并执行如下的命令,

[root@VM_0_4_centos ~]# cat cmd.txt | redis-cli --pipe
All data transferred. Waiting for the last reply...
Last reply received from server.
errors: 0, replies: 5

复制

这样,就执行了文本中保存的5条命令。而且通过抓包工具可以看出,可以通过一个数据包进行发送,而且跟 nc 相比,Redis 的回显也比较少。使用redis-cli进行查看。

[root@VM_0_4_centos ~]# redis-cli
127.0.0.1:6379> keys *
1) "k300"
2) "k200"
3) "k100"
127.0.0.1:6379> hgetall k300
1) "name"
2) "haha"
3) "age"
4) "20"
5) "gender"
6) "male"

复制

来查看一下关于 --pipe 命令的说明:

--pipe             Transfer raw Redis protocol from stdin to server.

复制

简单翻译一下的意思是,将原始 Redis 协议从标准输入中传输到服务器。

什么是原始的 Redis 协议,这点做一个简单的转换,当我们输入 “set key value” 时,Redis 转换的协议为:

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

复制

这个我们无法直接使用vim进行生成,原因在于\r\n是转义字符的回车和换行,我们使用代码来进行完成。

代码如下:

java.io.*;

GenerateRedisProtocol
{
    main(String[] args) IOException
    {
        System..println(args[]);

        GenerateRedisProtocol generateRedisProtocol = GenerateRedisProtocol();
        generateRedisProtocol.make(args[]);
    }

    make(String filePath) IOException
    {
        BufferedReader br = BufferedReader(FileReader(File(filePath)));
        BufferedWriter bw = BufferedWriter(FileWriter(filePath + ));

        String value=;

        ((value=br.readLine()) != ) {
            String proto = genRedisProto(value);

            bw.write(proto);
            bw.newLine();
        }

        bw.close();
        br.close();
    }

    String genRedisProto(String cmd)
    {
        String newStr[] = cmd.split();

        StringBuilder stringBuilder = StringBuilder();
        stringBuilder.append(+ newStr.+ );

        (String str: newStr) {
            stringBuilder.append(+ str.length() + );
            stringBuilder.append(str + );
        }

        String value = stringBuilder.toString();

        System..println(value);

        value;
    }
}

复制

写一个测试的文本,本文如下:

set k1 v1
set k2 v2
hset k3 name haha
hset k4 age 20

复制

对Java代码编译并运行,运行命令如下:

java GenerateRedisProtocol ./cmd.txt

复制

这样就会生成一个 cmd.txt.proto 的文件,文件内容如下:

*3
$3
set
$2
k1
$2
v1

*3
$3
set
$2
k2
$2
v2

复制

通过命令来导入该文件到 Redis 服务器中,命令如下:

[root@VM_0_4_centos ~]# cat cmd.txt.proto | redis-cli --pipe
All data transferred. Waiting for the last reply...
Last reply received from server.
errors: 0, replies: 4

复制

同样可以导入成功。

总结

redis-cli --pipe 可以大量插入数据,也可以从文件中批量插入数据。对于我们要手动为系统缓存一些数据到 Redis 时,可以通过数据库进行查询,查询后通过管道来进行导入。

转自:Redis | 管道 —— PipeLine - 云+社区 - 腾讯云

你可能感兴趣的:(redis,redis)