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源码
如有问题,欢迎评论或联系我。