redis 管道式操作
Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务。
这意味着通常情况下一个请求会遵循以下步骤:
- 客户端向服务端发送一个查询请求,并监听Socket返回,通常是以阻塞模式,等待服务端响应。
- 服务端处理命令,并将结果返回给客户端。
因此,例如下面是4个命令序列执行情况:
- Client: INCR X
- Server: 1
- Client: INCR X
- Server: 2
- Client: INCR X
- Server: 3
- Client: INCR X
- Server: 4
客户端和服务器通过网络进行连接。这个连接可以很快(loopback接口)或很慢(建立了一个多次跳转的网络连接)。无论网络延如何延时,数据包总是能从客户端到达服务器,并从服务器返回数据回复客户端。
这个时间被称之为 RTT (Round Trip Time - 往返时间). 当客户端需要在一个批处理中执行多次请求时很容易看到这是如何影响性能的(例如添加许多元素到同一个list,或者用很多Keys填充数据库)。例如,如果RTT时间是250毫秒(在一个很慢的连接下),即使服务器每秒能处理100k的请求数,我们每秒最多也只能处理4个请求。
如果采用loopback接口,RTT就短得多(比如我的主机ping 127.0.0.1只需要44毫秒),但它任然是一笔很多的开销在一次批量写入操作中。
幸运的是有一种方法可以改善这种情况。
Redis 管道(Pipelining)
redis 命令行操作在连接redis中,无法使用Pipeline管道操作,目前在主流的redis-client提供的SDK中均支持,
Java版本
Jedis jedis = new Jedis("localhost", 6379);
jedis.auth("[email protected]#$");
Pipeline pipeline = jedis.pipelined();
Long startTime = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
pipeline.lpush("test", "" + i);
}
pipeline.sync(); //将提交到队列中的命令执行
pipeline.close();
jedis.close();
log.info("endTime:" + (System.currentTimeMillis() - startTime));
Jedis jedisWithOutPipLine = new Jedis("localhost", 6379);
jedisWithOutPipLine.auth("[email protected]#$");
startTime = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
jedisWithOutPipLine.lpush("test", "" + i);
}
jedisWithOutPipLine.close();
log.info("endTime:" + (System.currentTimeMillis() - startTime));
打印结果如下
15:19:11.189 [main] INFO com.lesdo.util.ValidateUtils - endTime:47
15:19:11.706 [main] INFO com.lesdo.util.ValidateUtils - endTime:511
在第一种使用pipeline管道操作的情况下 速度相对快了10倍
Python版本
#encoding=utf-8
import redis
import time
redisClient = redis.StrictRedis(host="localhost",port=6379,password="[email protected]#$")
startTime = time.time()
pipeline = redisClient.pipeline()
for i in range(10000):
pipeline.lpush("test223",str(i))
pipeline.execute()
print time.time() - startTime
startTime = time.time()
for i in range(10000):
redisClient.lpush("sss",str(i))
print time.time() - startTime
执行结果如下:
0.14567899704
0.67511510849
因此相对来说 redis Pipeline管道操作相对速度是比较快的,在使用pipLine的时候,需要特别注意使用场景
由于PipeLine是批量执行命令,所有的命令将存在缓存区中,对物理内存和网络IO性能消耗较大
pipeLine管道操作,是连续执行命令,如果中间出现异常,不影响正常命令的执行,即是错误不影响任务的执行
所以对强数据准确的场景下,不适用。
另外pipeLine管道操作每个操作结果是统一返回,数据之前没有关联,
根据以上内容 得到结果如下
Pipeline使用场景:对大批量数据进行操作,并且这些数据没有强关联(如果有的话 建议使用Redis脚本(scripts)),
并且允许出现异常,有后续的容错机制
上一篇: MySQL查询效率问题解答