溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

redis中pipeline的介紹

發(fā)布時間:2020-05-27 09:58:49 來源:億速云 閱讀:408 作者:Leah 欄目:關(guān)系型數(shù)據(jù)庫

今天小編就為大家?guī)硪黄榻Bredis中pipeline的文章。小編覺得挺實用的,為此分享給大家做個參考。一起跟隨小編過來看看吧。

一、pipeline出現(xiàn)的背景:

redis執(zhí)行一條命令有四個過程:發(fā)送命令、命令排隊、命令執(zhí)行、返回結(jié)果;

這個過程稱為Round trip time(簡稱RTT, 往返時間),mget mset有效節(jié)約了RTT,但大部分命令(如hgetall,并沒有mhgetall)不支持批量操作,需要消耗N次RTT ,這個時候需要pipeline來解決這個問題。

二、pepeline的性能

1、未使用pipeline執(zhí)行N條命令

redis中pipeline的介紹

2、使用了pipeline執(zhí)行N條命令

redis中pipeline的介紹

3、兩者性能對比

redis中pipeline的介紹

小結(jié):這是一組統(tǒng)計數(shù)據(jù)出來的數(shù)據(jù),使用Pipeline執(zhí)行速度比逐條執(zhí)行要快,特別是客戶端與服務(wù)端的網(wǎng)絡(luò)延遲越大,性能體能越明顯。

下面貼出測試代碼分析兩者的性能差異:

	@Test
	public void pipeCompare() {
		Jedis redis = new Jedis("192.168.1.111", 6379);
		redis.auth("12345678");//授權(quán)密碼 對應(yīng)redis.conf的requirepass密碼
		Map<String, String> data = new HashMap<String, String>();
		redis.select(8);//使用第8個庫
		redis.flushDB();//清空第8個庫所有數(shù)據(jù)
		// 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); //循環(huán)執(zhí)行10000條數(shù)據(jù)插入redis
		}
		long end = System.currentTimeMillis();
		System.out.println("    共插入:[" + redis.dbSize() + "]條 .. ");
		System.out.println("1,未使用PIPE批量設(shè)值耗時" + (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對象,此時并未執(zhí)行,還停留在客戶端
		}
		pipe.sync(); //將封裝后的PIPE一次性發(fā)給redis
		end = System.currentTimeMillis();
		System.out.println("    PIPE共插入:[" + redis.dbSize() + "]條 .. ");
		System.out.println("2,使用PIPE批量設(shè)值耗時" + (end - start) / 1000 + "秒 ..");
//--------------------------------------------------------------------------------------------------
		// hmget
		Set<String> keys = redis.keys("key_*"); //將上面設(shè)值所有結(jié)果鍵查詢出來
		// 直接使用Jedis hgetall
		start = System.currentTimeMillis();
		Map<String, Map<String, String>> result = new HashMap<String, Map<String, String>>();
		for (String key : keys) {
			//此處keys根據(jù)以上的設(shè)值結(jié)果,共有10000個,循環(huán)10000次
			result.put(key, redis.hgetAll(key)); //使用redis對象根據(jù)鍵值去取值,將結(jié)果放入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,此時還停留在客戶端,并未真正執(zhí)行查詢請求
		}
		pipe.sync();  //提交到redis進行查詢
		
		end = System.currentTimeMillis();
		System.out.println("    PIPE共取值:[" + redis.dbSize() + "]條 .. ");
		System.out.println("4,使用PIPE批量取值耗時" + (end - start) / 1000 + "秒 ..");

		redis.disconnect();
	}

redis中pipeline的介紹

三、原生批命令(mset, mget)與Pipeline對比

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

(原子性概念:一個事務(wù)是一個不可分割的最小工作單位,要么都成功要么都失敗。原子操作是指你的一個業(yè)務(wù)邏輯必須是不可拆分的. 處理一件事情要么都成功,要么都失敗,原子不可拆分)

2、原生批命令一命令多個key, 但pipeline支持多命令(存在事務(wù)),非原子性

3、原生批命令是服務(wù)端實現(xiàn),而pipeline需要服務(wù)端與客戶端共同完成

四、Pipeline正確使用方式

使用pipeline組裝的命令個數(shù)不能太多,不然數(shù)據(jù)量過大,增加客戶端的等待時間,還可能造成網(wǎng)絡(luò)阻塞,可以將大量命令的拆分多個小的pipeline命令完成。

1、Jedis中的pipeline使用方式

大家知道redis提供了mset、mget方法,但沒有提供mdel方法,如果想實現(xiàn),可以借助pipeline實現(xiàn)。

2、Jedis中的pipeline使用步驟:

  • 獲取jedis對象(一般從連接池中獲取)

  • 獲取jedis對象的pipeline對象

  • 添加指令

  • 執(zhí)行指令

測試類方法:

	 @Test
	public void testCommond() {
		// 工具類初始化
		JedisUtils jedis = new JedisUtils("192.168.1.111", 6379, "12345678");

		for (int i = 0; i < 100; i++) {
			// 設(shè)值
			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(); //執(zhí)行命令,完全此時pipeline對象的遠程調(diào)用 
			flag = true;
		} catch (Exception e) {
			pool.returnBrokenResource(jedis);
			e.printStackTrace();
		} finally {
			returnResource(pool, jedis);
		}
		return flag;
	}

使用pipeline提交所有操作并返回執(zhí)行結(jié)果:

@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"); // 調(diào)值
		pipe.incr("age");// 自增
		pipe.get("name");
		pipe.discard();
		// 將不同類型的操作命令合并提交,并將操作操作以list返回
		List<Object> list = pipe.syncAndReturnAll();

		for (Object obj : list) {
			// 將操作結(jié)果打印出來
			System.out.println(obj);
		}
		// 斷開連接,釋放資源
		jedis.disconnect();
	}

五、redis事務(wù)

pipeline是多條命令的組合,為了保證它的原子性,redis提供了簡單的事務(wù)。

1、redis的簡單事務(wù),

一組需要一起執(zhí)行的命令放到multi和exec兩個命令之間,其中multi代表事務(wù)開始,exec代表事務(wù)結(jié)束。

redis中pipeline的介紹

2、停止事務(wù)discard

redis中pipeline的介紹

3、命令錯誤,語法不正確,導(dǎo)致事務(wù)不能正常結(jié)束

redis中pipeline的介紹

4、運行錯誤,語法正確,但類型錯誤,事務(wù)可以正常結(jié)束

redis中pipeline的介紹

5、watch命令:

使用watch后, multi失效,事務(wù)失效

redis中pipeline的介紹

WATCH的機制是:在事務(wù)EXEC命令執(zhí)行時,Redis會檢查被WATCH的key,只有被WATCH的key從WATCH起始時至今沒有發(fā)生過變更,EXEC才會被執(zhí)行。如果WATCH的key在WATCH命令到EXEC命令之間發(fā)生過變化,則EXEC命令會返回失敗。

看完上述內(nèi)容,你們對redis中的pipeline大概了解了嗎?如果想了解更多相關(guān)文章內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI