jedis中rpop操作刪除的簡要分析
學習使人進步,為了提升性能,保證HA,運維想把redis也弄成redis集群,陪他玩的任務自然就落在了最近有點閑的我的身上。在測試過程中需要模擬很多場景,其中一個場景是:用戶使用rpop讀取list信息時,未傳輸結束的時候,主redis突然發生問題,進入重連。這條數據是否會被刪除?或是刪除一部分?亦或者是完全沒有刪除操作?這引起我的思考。
如果文章內容有問題,歡迎評論或與我進行討論(請注明原因):
mail: wgh0807@qq.com
微信: hello-wgh0807
qq: 490536401
結論
如果在傳輸過程中突然redis異常,redis不會進行刪除操作。rpop將value值作為一個整體,不會作為字節流邊刪邊傳。具體流程見下文。
實驗過程:
-
編寫了一個簡單的java Application,用於獲取redis中List類型對象的每一項value。
private void redisClusterTesr() { String host = "localhost"; Integer port = 6379; String password = "test"; String name = "Thread1"; // 和redis服務器建立連接 Jedis jedis = new Jedis(host, port); try { jedis.auth(password); } catch (JedisConnectionException e) { System.err.println(name + "無法連接至目的主機!" + host + ":" + port); return; } catch (JedisDataException e) { System.err.println(name + "密碼錯誤,登陸失敗!" + e.getMessage()); return; } System.out.println(); // 獲取存儲的數據並輸出 long size = jedis.llen(name); List<String> list = new ArrayList<>(); // 循環進行rpop,拋出每個 for (int i = 0; i < size; i++) { try { String str = jedis.rpop(name); list.add(str); System.out.println(name+" 獲取成功,ID:"+i); } catch (JedisConnectionException e) { System.err.println(name + "連接已斷開,正在准備重新連接"); boolean result = false; for (int j = 0; j < 10; j++) { jedis.close(); jedis = new Jedis(host, port); try { jedis.auth(password); System.err.println(name + "第 /10次重新連接:連接成功"); i--; } catch (JedisConnectionException e1) { System.err.println(name + "第 /10次重新連接:連接失敗"); } } } } System.out.println("finish,size: "+list.size()); System.out.println(Arrays.toString(list.toArray())); }
-
在其中第28行,即
String str = jedis.rpop(name);
處增加斷點 -
正常執行(resume,idea快捷鍵F9)一至兩項后,選擇Step into 按鈕查看下層實現代碼(idea快捷鍵F7)。
-
觀察代碼,總結流程
rpop流程圖
ps:基本就是這樣,若傳輸時網絡異常,沒有傳輸完成,將拋出IO異常(可能被上層捕獲並轉換為JedisConnectionException,這里沒有注意)。不會發送確認並刪除請求。
總結
這個問題雖然解決了,但jedis和redis對我而言依舊神秘,我編寫的測試數據為30線程*2000w條數據,共6億條數據,每條數據5k,在不到30s便擠爆了32G服務器的50G硬盤,且停止運行的原因是磁盤不足,而不是內存不足。
redis的高效率超出了我的想象,不是一個簡簡單單的‘小工具’。有機會一定要讀一下他的源代碼,一定有所收獲。
參考文獻:
jedis源碼
如有問題,歡迎評論或聯系我。