redis中pipeline详解

redis中pipeline详解

一、pipeline出现的背景:

redis执行一条命令有四个过程:发送命令、命令排队、命令执行、返回结果;

这个过程称为Round trip time(简称RTT, 往返时间),mget mset有效节约了RTT,但大部分命令(如hgetall,并没有mhgetall)不支持批量操作,需要消耗N次RTT ,这个时候需要pipeline来解决这个问题。

二、pepeline的性能

1、未使用pipeline执行N条命令

redis中pipeline详解

2、使用了pipeline执行N条命令

redis中pipeline详解

3、两者性能对比

redis中pipeline详解

小结:这是一组统计数据出来的数据,使用Pipeline执行速度比逐条执行要快,特别是客户端与服务端的网络延迟越大,性能体能越明显。

下面贴出测试代码分析两者的性能差异:

	@Test 	public void pipeCompare() { 		Jedis redis = new Jedis("192.168.1.111", 6379); 		redis.auth("12345678");//授权密码 对应redis.conf的requirepass密码 		Map<string> data = new HashMap<string>(); 		redis.select(8);//使用第8个库 		redis.flushDB();//清空第8个库所有数据 		// hmset 		long start = System.currentTimeMillis(); 		// 直接hmset 		for (int i = 0; i  keys = redis.keys("key_*"); //将上面设值所有结果键查询出来 		// 直接使用Jedis hgetall 		start = System.currentTimeMillis(); 		Map<string>&gt; result = new HashMap<string>&gt;(); 		for (String key : keys) { 			//此处keys根据以上的设值结果,共有10000个,循环10000次 			result.put(key, redis.hgetAll(key)); //使用redis对象根据键值去取值,将结果放入result对象 		} 		end = System.currentTimeMillis(); 		System.out.println("    共取值:[" + redis.dbSize() + "]条 .. "); 		System.out.println("3,未使用PIPE批量取值耗时 " + (end - start) / 1000 + "秒 ..");  		// 使用pipeline hgetall 		result.clear(); 		start = System.currentTimeMillis(); 		for (String key : keys) { 			pipe.hgetAll(key); //使用PIPE封装需要取值的key,此时还停留在客户端,并未真正执行查询请求 		} 		pipe.sync();  //提交到redis进行查询 		 		end = System.currentTimeMillis(); 		System.out.println("    PIPE共取值:[" + redis.dbSize() + "]条 .. "); 		System.out.println("4,使用PIPE批量取值耗时" + (end - start) / 1000 + "秒 ..");  		redis.disconnect(); 	}</string></string></string></string>

redis中pipeline详解

三、原生批命令(mset, mget)与Pipeline对比

1、原生批命令是原子性,pipeline是非原子性

(原子性概念:一个事务是一个不可分割的最小工作单位,要么都成功要么都失败。原子操作是指你的一个业务逻辑必须是不可拆分的. 处理一件事情要么都成功,要么都失败,原子不可拆分)

2、原生批命令一命令多个key, 但pipeline支持多命令(存在事务),非原子性

3、原生批命令是服务端实现,而pipeline需要服务端与客户端共同完成

四、Pipeline正确使用方式

使用pipeline组装的命令个数不能太多,不然数据量过大,增加客户端的等待时间,还可能造成网络阻塞,可以将大量命令的拆分多个小的pipeline命令完成。

1、Jedis中的pipeline使用方式

大家知道redis提供了mset、mget方法,但没有提供mdel方法,如果想实现,可以借助pipeline实现。

2、Jedis中的pipeline使用步骤:

  • 获取jedis对象(一般从连接池中获取)

  • 获取jedis对象的pipeline对象

  • 添加指令

  • 执行指令

测试类方法:

	 @Test 	public void testCommond() { 		// 工具类初始化 		JedisUtils jedis = new JedisUtils("192.168.1.111", 6379, "12345678");  		for (int i = 0; i  keys = new ArrayList<string>(); 		for (int i = 0; i <p>JedisUtils下的mdel方法:</p> <pre class="brush:php;toolbar:false">	/** 	 * 删除多个字符串key 并释放连接 	 *  	 * @param keys* 	 * @return 成功返回value 失败返回null 	 */ 	public boolean mdel(List<string> keys) { 		Jedis jedis = null; 		boolean flag = false; 		try { 			jedis = pool.getResource();//从连接借用Jedis对象 			Pipeline pipe = jedis.pipelined();//获取jedis对象的pipeline对象 			for(String key:keys){ 				pipe.del(key); //将多个key放入pipe删除指令中 			} 			pipe.sync(); //执行命令,完全此时pipeline对象的远程调用  			flag = true; 		} catch (Exception e) { 			pool.returnBrokenResource(jedis); 			e.printStackTrace(); 		} finally { 			returnResource(pool, jedis); 		} 		return flag; 	}</string>

使用pipeline提交所有操作并返回执行结果:

@Test 	public void testPipelineSyncAll() { 		// 工具类初始化 		Jedis jedis = new Jedis("192.168.1.111", 6379); 		jedis.auth("12345678"); 		// 获取pipeline对象 		Pipeline pipe = jedis.pipelined(); 		pipe.multi(); 		pipe.set("name", "james"); // 调值 		pipe.incr("age");// 自增 		pipe.get("name"); 		pipe.discard(); 		// 将不同类型的操作命令合并提交,并将操作操作以list返回 		List<object> list = pipe.syncAndReturnAll();  		for (Object obj : list) { 			// 将操作结果打印出来 			System.out.println(obj); 		} 		// 断开连接,释放资源 		jedis.disconnect(); 	}</object>

五、redis事务

pipeline是多条命令的组合,为了保证它的原子性,redis提供了简单的事务。

1、redis的简单事务,

一组需要一起执行的命令放到multi和exec两个命令之间,其中multi代表事务开始,exec代表事务结束。

redis中pipeline详解

2、停止事务discard

redis中pipeline详解

3、命令错误,语法不正确,导致事务不能正常结束

redis中pipeline详解

4、运行错误,语法正确,但类型错误,事务可以正常结束

redis中pipeline详解

5、watch命令:

使用watch后, multi失效,事务失效

redis中pipeline详解

WATCH的机制是:在事务EXEC命令执行时,Redis会检查被WATCH的key,只有被WATCH的key从WATCH起始时至今没有发生过变更,EXEC才会被执行。如果WATCH的key在WATCH命令到EXEC命令之间发生过变化,则EXEC命令会返回失败。

更多redis知识请关注redis入门教程栏目。

以上就是

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享