Redis之管道

概念

Redis是一个响应式的服务,当客户端发送一个请求后,就处于阻塞状态等待Redis返回结果。这样一次命令消耗的时间就包括四个部分:请求从客户端到服务器的时间命令排队的时间命令真正执行时间、结果从服务器到客户端的时间,第一个和第四个消耗的时间总和称为RTT(Round Trip Time),当客户端与服务器存在网络延时时,RTT就可能会很大,这样就会导致性能问题。

管道(Pipeline)就是为了改善这个情况的,利用管道,客户端可以一次性发送多个请求而不用等待服务器的响应,待所有命令都发送完后再一次性读取服务的响应,这样可以极大的降低RTT时间从而提升性能。需要注意到是用pipeline方式打包命令发送,redis必须在处理完所有命令前先缓存起所有命令的处理结果。打包的命令越多,缓存消耗内存也越多。所以并不是打包的命令越多越好。

pipeline和“事务”是两个完全不同的概念,pipeline只是表达“交互”中操作的传递的方向性,pipeline也可以在事务中运行,也可以不在。无论如何,pipeline中发送的每个command都会被server立即执行,如果执行失败,将会在此后的响应中得到信息;也就是pipeline并不是表达“所有command都一起成功”的语义;但是如果pipeline的操作被封装在事务中,那么将有事务来确保操作的成功与失败。

对比分析

Redis提供了批量操作命令,如mget,mset,但有些命令不支持批量操作,如果有一个场景需要批量操作某些key,假如有1000个,在我们没有使用批量操作时所需要的时间是1000次RTT时间+1000次命令执行时间:

Redis之管道_第1张图片
    2.使用pipeline操作一次传递命令时,所需要的时间是1次RTT时间+1000次命令执行时间:
    Redis之管道_第2张图片

举例分析
测试不使用pipeline和使用pipeline分别向redis中存放一千条

@Test
public void testNoPipelineSet() {
	Jedis jedis = jedisPool.getResource();
	String keyPrefix = "normal";
	long begin = System.currentTimeMillis();
	for (int i = 1; i < 10000; i++) {
		String key = keyPrefix + "_" + i;
		String value = String.valueOf(i);
		jedis.set(key, value);
	}
	jedis.close();
	long end = System.currentTimeMillis();
	System.out.println("not use pipeline batch set total time:" + (end - begin));
}

@Test
public void testPipelineSet() {
	Jedis jedis = jedisPool.getResource();
	Pipeline pipelined = jedis.pipelined();
	String keyPrefix = "pipeline";
	long begin = System.currentTimeMillis();
	for (int i = 1; i < 10000; i++) {
		String key = keyPrefix + "_" + i;
		String value = String.valueOf(i);
		pipelined.set(key, value);
        }
        pipelined.sync();
        jedis.close();
        long end = System.currentTimeMillis();
        System.out.println("use pipeline batch set total time:" + (end - begin));
}

结果

not use pipeline batch set total time:998
use pipeline batch set total time:31

使用了pipeline后提升效果非常明显。

事务、管道和脚本的区别

1. 事务和脚本从原子性上来说都能满足原子性的要求,其区别在于脚本可借助Lua语言可在服务器端存储的便利性定制和简化操作,但脚本无法处理长耗时的操作。redis确保这条script脚本执行期间,其它任何脚本或者命令都无法执行。正是由于这种原子性,script才可以替代MULTI/EXEC作为事务使用。当然,官方文档也说了,正是由于script执行的原子性,所以我们不要在script中执行过长开销的程序,否则会验证影响其它请求的执行。

2. 管道是无状态操作集合,使用管道可能在效率上比使用script要好,但是有的情况下只能使用script。因为在执行后面的命令时,无法得到前面命令的结果,就像事务一样,所以如果需要在后面命令中使用前面命令的value等结果,则只能使用script或者事务+watch。

你可能感兴趣的:(#,Redis)