Redis 管道pipeline
2017-02-10 16:00
309 查看
Redis是一个cs模式的tcp server,使用和http类似的请求响应协议。一个client可以通过一个socket连接发起多个请求命令。每个请求命令发出后client通常会阻塞并等待redis服务处理,redis处理完后请求命令后会将结果通过响应报文返回给client。基本的通信过程如下:
[plain] view
plain copy
print?
./bin/redis-cli -h 192.168.36.189 -p 6379
192.168.36.189:6379> incr x
(integer) 1
192.168.36.189:6379> incr x
(integer) 2
192.168.36.189:6379> incr x
(integer) 3
客户端和服务端通过网络进行连接。这样的连接可能非常快(在一个回路网络中),也可能非常慢(在广域网上经过多个结点才能互通的两个主机)。但是无论是否存在网络延迟,数据包从客户端传输到服务端,以及客户端从服务端获得相应都需要花费一些时间。这段时间就成为往返时延(Round Trip Time)。因此当客户端需要执行一串请求的时候,很容易看出它对性能的影响(例如往同一个队列中加入大量元素,或者往数据库中插入大量的键)。如果RTT时长为250毫秒(在基于广域网的低速连接环境下),即使服务器每秒可以处理10万个请求,但是实际上我们依然只能每秒处理最多4个请求。
如果处于一个回路网络中,RTT时长则相当短(我的主机ping 127.0.0.1时只需要0.044ms),但是如果你执行一大串写入请求的时候,还是会有点长。
幸运的是,redis给我们提供了管道技术。
1.Redis管道技术
一个请求/相应服务可以实现为,即使客户端没有读取到旧请求的响应,服务端依旧可以处理新请求。通过这种方式,可以完全无需等待服务端应答地发送多条指令给服务端,并最终一次性读取所有应答。管道技术最显著的优势是提高了redis服务的性能。
通过pipeline方式当有大批量的操作时候。我们可以节省很多原来浪费在网络延迟的时间。需要注意到是用pipeline方式打包命令发送,redis必须在处理完所有命令前先缓存起所有命令的处理结果。打包的命令越多,缓存消耗内存也越多。所以并是不是打包的命令越多越好。具体多少合适需要根据具体情况测试。
[plain] view
plain copy
print?
$(echo -en "PING\r\n SET key redis\r\nGET key\r\nINCR x\r\nINCR x\r\nINCR x\r\n"; sleep 10) | nc 192.168.36.189 6379
+PONG
+OK
$5
redis
:4
:5
:6
以上实例中我们通过使用 PING 命令查看redis服务是否可用, 之后我们们设置了key的值为 redis,然后我们获取key 的值并使得x自增 3 次。
在返回的结果中我们可以看到这些命令一次性向redis服务提交,并最终一次性读取所有服务端的响应。
2.java测试代码
[java] view
plain copy
print?
package cn.slimsmart.redis.demo.pipeline;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
@SuppressWarnings("resource")
public class PipelineTest {
public static void main(String[] args) {
long start = System.currentTimeMillis();
usePipeline();
long end = System.currentTimeMillis();
System.out.println("usePipeline:"+(end - start));
start = System.currentTimeMillis();
withoutPipeline();
end = System.currentTimeMillis();
System.out.println("withoutPipeline:"+(end - start));
}
private static void withoutPipeline() {
try {
Jedis jedis = new Jedis("192.168.36.189", 6379);
for (int i = 0; i < 1000; i++) {
jedis.incr("test2");
}
jedis.disconnect();
} catch (Exception e) {
}
}
private static void usePipeline() {
try {
Jedis jedis = new Jedis("192.168.36.189", 6379);
Pipeline pipeline = jedis.pipelined();
for (int i = 0; i < 1000; i++) {
pipeline.incr("test2");
}
pipeline.sync();
jedis.disconnect();
} catch (Exception e) {
}
}
}
运行结果:
usePipeline:125
withoutPipeline:8607
结果还是很明显有较大的差距,所以多次操作用pipeline还是有明显的优势。
[plain] view
plain copy
print?
./bin/redis-cli -h 192.168.36.189 -p 6379
192.168.36.189:6379> incr x
(integer) 1
192.168.36.189:6379> incr x
(integer) 2
192.168.36.189:6379> incr x
(integer) 3
客户端和服务端通过网络进行连接。这样的连接可能非常快(在一个回路网络中),也可能非常慢(在广域网上经过多个结点才能互通的两个主机)。但是无论是否存在网络延迟,数据包从客户端传输到服务端,以及客户端从服务端获得相应都需要花费一些时间。这段时间就成为往返时延(Round Trip Time)。因此当客户端需要执行一串请求的时候,很容易看出它对性能的影响(例如往同一个队列中加入大量元素,或者往数据库中插入大量的键)。如果RTT时长为250毫秒(在基于广域网的低速连接环境下),即使服务器每秒可以处理10万个请求,但是实际上我们依然只能每秒处理最多4个请求。
如果处于一个回路网络中,RTT时长则相当短(我的主机ping 127.0.0.1时只需要0.044ms),但是如果你执行一大串写入请求的时候,还是会有点长。
幸运的是,redis给我们提供了管道技术。
1.Redis管道技术
一个请求/相应服务可以实现为,即使客户端没有读取到旧请求的响应,服务端依旧可以处理新请求。通过这种方式,可以完全无需等待服务端应答地发送多条指令给服务端,并最终一次性读取所有应答。管道技术最显著的优势是提高了redis服务的性能。
通过pipeline方式当有大批量的操作时候。我们可以节省很多原来浪费在网络延迟的时间。需要注意到是用pipeline方式打包命令发送,redis必须在处理完所有命令前先缓存起所有命令的处理结果。打包的命令越多,缓存消耗内存也越多。所以并是不是打包的命令越多越好。具体多少合适需要根据具体情况测试。
[plain] view
plain copy
print?
$(echo -en "PING\r\n SET key redis\r\nGET key\r\nINCR x\r\nINCR x\r\nINCR x\r\n"; sleep 10) | nc 192.168.36.189 6379
+PONG
+OK
$5
redis
:4
:5
:6
以上实例中我们通过使用 PING 命令查看redis服务是否可用, 之后我们们设置了key的值为 redis,然后我们获取key 的值并使得x自增 3 次。
在返回的结果中我们可以看到这些命令一次性向redis服务提交,并最终一次性读取所有服务端的响应。
2.java测试代码
[java] view
plain copy
print?
package cn.slimsmart.redis.demo.pipeline;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
@SuppressWarnings("resource")
public class PipelineTest {
public static void main(String[] args) {
long start = System.currentTimeMillis();
usePipeline();
long end = System.currentTimeMillis();
System.out.println("usePipeline:"+(end - start));
start = System.currentTimeMillis();
withoutPipeline();
end = System.currentTimeMillis();
System.out.println("withoutPipeline:"+(end - start));
}
private static void withoutPipeline() {
try {
Jedis jedis = new Jedis("192.168.36.189", 6379);
for (int i = 0; i < 1000; i++) {
jedis.incr("test2");
}
jedis.disconnect();
} catch (Exception e) {
}
}
private static void usePipeline() {
try {
Jedis jedis = new Jedis("192.168.36.189", 6379);
Pipeline pipeline = jedis.pipelined();
for (int i = 0; i < 1000; i++) {
pipeline.incr("test2");
}
pipeline.sync();
jedis.disconnect();
} catch (Exception e) {
}
}
}
运行结果:
usePipeline:125
withoutPipeline:8607
结果还是很明显有较大的差距,所以多次操作用pipeline还是有明显的优势。
相关文章推荐
- Redis 管道pipeline
- Redis学习笔记7--Redis管道(pipeline)
- 012redis管道(pipeline)
- redis 性能优化优化提升之管道(pipeline)
- redis管道(pipeline)
- Redis学习笔记7--Redis管道(pipeline)
- Redis学习笔记7--Redis管道(pipeline)
- Redis 新特性---pipeline(管道)
- Redis管道(pipeline)
- .NET客户端实现Redis中的管道(PipeLine)与事物(Transactions)(八)
- .NET客户端实现Redis中的管道(PipeLine)与事物(Transactions)
- Redis管道(pipeline)
- 分布式缓存Redis之Pipeline(管道)
- redis基础简介(六)- jedis使用管道(pipeline)对redis进行读写(使用hmset、hgetall测试)
- .NET客户端实现Redis中的管道(PipeLine)与事物(Transactions)
- Redis管道Pipeline使用
- .NET客户端实现Redis中的管道(PipeLine)与事物(Transactions)
- redis 使用管道提升写入的性能[pipeline]
- redis集群客户端JedisCluster优化 - 管道(pipeline)模式支持
- Redis 新特性---pipeline(管道)