问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

redis的.net版本客户端中pipeline怎么用

发布网友 发布时间:2022-04-11 13:55

我来回答

2个回答

懂视网 时间:2022-04-11 18:16

一、pipeline出现的背景:

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

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

二、pepeline的性能

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

1.jpg

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

2.jpg

3、两者性能对比

3.jpg

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

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

	@Test
	public void pipeCompare() {
		Jedis redis = new Jedis("192.168.1.111", 6379);
		redis.auth("12345678");//授权密码 对应redis.conf的requirepass密码
		Map<String, String> data = new HashMap<String, String>();
		redis.select(8);//使用第8个库
		redis.flushDB();//清空第8个库所有数据
		// hmset
		long start = System.currentTimeMillis();
		// 直接hmset
		for (int i = 0; i < 10000; i++) {
			data.clear(); //清空map
			data.put("k_" + i, "v_" + i);
			redis.hmset("key_" + i, data); //循环执行10000条数据插入redis
		}
		long end = System.currentTimeMillis();
		System.out.println(" 共插入:[" + redis.dbSize() + "]条 .. ");
		System.out.println("1,未使用PIPE批量设值耗时" + (end - start) / 1000 + "秒..");
		redis.select(8);
		redis.flushDB();
		// 使用pipeline hmset
		Pipeline pipe = redis.pipelined();
		start = System.currentTimeMillis();
		//
		for (int i = 0; i < 10000; i++) {
			data.clear();
			data.put("k_" + i, "v_" + i);
			pipe.hmset("key_" + i, data); //将值封装到PIPE对象,此时并未执行,还停留在客户端
		}
		pipe.sync(); //将封装后的PIPE一次性发给redis
		end = System.currentTimeMillis();
		System.out.println(" PIPE共插入:[" + redis.dbSize() + "]条 .. ");
		System.out.println("2,使用PIPE批量设值耗时" + (end - start) / 1000 + "秒 ..");
//--------------------------------------------------------------------------------------------------
		// hmget
		Set<String> keys = redis.keys("key_*"); //将上面设值所有结果键查询出来
		// 直接使用Jedis hgetall
		start = System.currentTimeMillis();
		Map<String, Map<String, String>> result = new HashMap<String, Map<String, String>>();
		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();
	}

4.jpg

三、原生批命令(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 < 100; i++) {
    			// 设值
    			jedis.set("n" + i, String.valueOf(i));
    		}
    		System.out.println("keys from redis return =======" + jedis.keys("*"));
    
    	}
    
    	// 使用pipeline批量删除
    	 @Test
    	public void testPipelineMdel() {
    		// 工具类初始化
    		JedisUtils jedis = new JedisUtils("192.168.1.111", 6379, "12345678");
    		List<String> keys = new ArrayList<String>();
    		for (int i = 0; i < 100; i++) {
    			keys.add("n" + i);
    		}
    		jedis.mdel(keys);
    		System.out.println("after mdel the redis return ---------" + jedis.keys("*"));
    	}

    JedisUtils下的mdel方法:

    	/**
    	 * 删除多个字符串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;
    	}

    使用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();
    	}

    五、redis事务

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

    1、redis的简单事务,

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

    5.jpg

    2、停止事务discard

    6.JPG

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

    7.jpg

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

    8.jpg

    5、watch命令:

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

    9.jpg

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

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

    热心网友 时间:2022-04-11 15:24

      1、Redis本身是一个cs模式的tcp
    server,
    client可以通过一个socket连续发起多个请求命令。
    每个请求命令发出后client通常会阻塞并等待redis服务端处理,redis服务端处理完后将结果返回给client。
      
      2、redis的pipeline(管道)功能在命令行中没有,但redis是支持pipeline的,而且在各个语言版的client中都有相应的实现。

      
      3、Pipeline在某些场景下非常有用,比如有多个command需要被“及时的”提交,而且他们对相应结果没有互相依赖,而且对结果响应也无需立即获得,那么pipeline就可以充当这种“批处理”的工具;而且在一定程度上,可以较大的提升性能,性能提升的原因主要是TCP链接中较少了“交互往返”的时间。
      4、不过在编码时请注意,pipeline期间将“独占”链接,此期间将不能进行非“管道”类型的其他操作,直到pipeline关闭;
    声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
    男生买卫生巾支援灾区对吗? 打了耳洞三天下了耳钉,怎么办!! cs七龙珠家里两台电脑怎么连局域网玩 CS七龙珠怎么创建联网房间 CS七龙珠怎样和电脑玩 CS七龙珠能和电脑对打吗 不然怎样调对打模式有哪些地图!!!急需... 糖葫芦的山楂在哪里买 衡水市康宁街与人民路交叉口市一建家属院7号楼,1-201怎么翻译 梦见朋友搬家时小孩因我不愿离去,且小孩坐在床上跑出许老鼠? 梦见搬家是什么预兆解梦 redis秒杀到底是用集合还是队列呢 Redis持久化方案该如何选型 redis这个技术是怎么出现的,他的出现背景是什么 php redis 有密码怎么连接 为什么加锁和解锁必须在一个数据库连接中,否则可能解锁失败? 怎样对一个TCODE进行加锁和解锁? redis 多个请求对一个key 实现 读取操作并发下怎么加锁 redis 多个请求对一个key 实现 读取操作.并发下.怎么加锁 redis会对数据加锁吗? php 怎么给redis加查询锁 redis集成spring到缓存什么位置 spring boot集成redis需要添加哪些依赖 spring整合redis时怎么把数据放到缓存里 springboot缓存怎么来操作 如何将多个redis查询命令合并成一个执行 向数据库中添加信息的sql语句,如何写,为什么datatime类型会报错? 每天向sql2005数据库里添加记录的作业命令怎么写 asp中为SQL数据库中增加一条记录的语句是什么 在C#中,如何使用sql语句向数据库中添加信息 如果要把数据库文件添加到sql软件里,你应该使用什么命令? redis的pipeline和mget有什么区别 redis pipeline可以提交多少 redis中pipeline怎么样传参数进去 redis 一个管道pipeline是顺序执行的吗 redis pipeline mget 哪个 redis集群不支持discard操作 redis pipeline 多少条已提交比较好 为什么它是有10万的记录,以便使用慢pipelineredis的时候 redis 怎么计算数据占用内存 redis monitor界面怎么看 请问java的商城订单模块,如何解决用户恶意创建订单,但是不支付的问题? 求详细解决方案。 redis如何实现订单失效通知 在淘宝上要完成一笔订单,会有哪些参与者一起协同? 使用redis支付安全吗 shiro redis过期时间设置多少 redis的rpop方法在多线程操作时,能保证原子性吗 redis 怎么做条件查询 怎么把32位的redis部署到windows下 redis-2.8.21怎么部署 redis使用有什么注意点没有