jedisPool使用遇到的bug
这个是今天发现一个bug:在测试redis并发读写的时候(jedis作为客户端,并使用了连接池),总是报用完jedis无法返回jedisPool
Caused by: redis.clients.jedis.exceptions.JedisException: Could not return the resource to the pool at redis.clients.util.Pool.returnResourceObject(Pool.java:69) at redis.clients.jedis.JedisPool.returnResource(JedisPool.java:253) ... 14 more Caused by: java.lang.IllegalStateException: Object has already been returned to this pool or is invalid at org.apache.commons.pool2.impl.GenericObjectPool.returnObject(GenericObjectPool.java:538) at redis.clients.util.Pool.returnResourceObject(Pool.java:67) ... 15 more
或者
Exception in thread "Thread-71" java.lang.ClassCastException: java.lang.Long cannot be cast to [B at redis.clients.jedis.Connection.getBinaryBulkReply(Connection.java:259) at redis.clients.jedis.Connection.getBulkReply(Connection.java:248) at redis.clients.jedis.Jedis.lpop(Jedis.java:1055) at us.codecraft.webmagic.scheduler.RedisScheduler.poll(RedisScheduler.java:77) at us.codecraft.webmagic.Spider.run(Spider.java:308) at java.lang.Thread.run(Thread.java:748)
类似的错误,就是返回值类型和文档上的返回值类型不相符,感觉很不应该;开始怀疑是jedis实现的一个bug,后来发现一个现象,当抛一个超时异常的时候,后面就连续的出现一个类似上面的错误,最后终于发现了问题所在。
原先的代码是这样的:
public void releaseResource() { if (this.jedis != null) { jedisPool.returnResource(jedis); } }
发现returnResource被标记为废弃,查看jedis源代码发现了close()方法
public void close() { if (this.dataSource != null) { if (this.client.isBroken()) { this.dataSource.returnBrokenResource(this); } else { this.dataSource.returnResource(this); } } else { this.client.close(); } }
这个问题已经有前辈遇到过了,其解释:
查看 Jedis 源码发现它的Connection中对网络输出流做了一个封装(RedisInputStream),其中自建了一个buffer。当发生异常的时候,这个buffer里还残存着上次没有发送或者发送不完整的命令。这个时候没有做处理,直接将该连接返回到连接池,那么重用该连接执行下次命令的时候,就会将上次没有发送的命令一起发送过去,所以才会出现上面的错误“返回值类型不对”。
所以,正确的写法应该是:在发送异常的时候,销毁这个连接,不能再重用!
于是修改代码为
public void releaseResource() { if (this.jedis != null) { try { jedis.close(); } catch (Exception e) { log.error("释放jedis资源出错,将要关闭jedis,异常信息:" + e.getMessage()); if (jedis != null) { try { // 2. 客户端主动关闭连接 jedis.disconnect(); } catch (Exception e1) { log.error("disconnect jedis connection fail: " , e); }finally { } } } } }
这样经过测试解决了jedis用完无法返回jedisPool的问题。但是java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.Long 类型转换的错误依然存在。
于是把多线程的测试环境改为单线程,单个线程调用jedis不再出现问题。但是违背了初衷。把使用jedis的对象加锁,同时只有一个对象使用同一个jedis,如果因为
Jedis “Socket读取超时”导致“返回值类型错误”
还是可能出现这个问题(不过几率较小了),调用releaseReource方法销毁jedis对象,重新从jedisPool获得一个,不要用之前的jedis对象,问题解决
参考:
http://bert82503.iteye.com/blog/2184225
https://github.com/xetorthio/jedis/issues/186

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
区块链开发公司谈区块链技术的应用
区块链用数字技术解决了信任问题,解决了信息的真实性、完整性和可追溯性问题,对当下互联网发展非常重要。“之前互联网的信任问题没有很好的解决办法,仍旧是靠一个大公司的主体信用担保,这违背了互联网开放的初心,也不能充分发挥互联网的潜能。” 而区块链技术的出现,让解决信任问题的成本变得极低,从而将会进一步盘活各行各业的活力。 同时,区块链善于解决数据的资产属性问题,而数据是人工智能发展的核心要素。通过区块链,可以更有效地构建一个数据互融互通的生态,进一步促进人工智能的发展。 区块链技术的破坏性力量创新了我们的数据存储方式,允许用户完全控制他们希望在公共场合分享的个人详细信息。利用区块链技术和权力下放的潜力可能是保护我们隐私的关键。 技术进步揭示了通过区块链技术管理我们数据的另一种方式。但这种方法并不是新颖的,事实上,它可以追溯到一些最早的互联网概念。权力下放为我们今天所知的无与伦比的万维网奠定了基础。它也是区块链技术的核心特征。 区块链技术的本质是一个数据库,那么我们能否建立一个这样的数据库,它包罗万象,记录这个世界上每个人的一切活动。那么区块链技术就如同时间和空间的总和,即宇宙。通过宇宙的去...
- 下一篇
JavaScript 为什么快--第二篇
上一篇,我们介绍了 V8 引擎的执行管道架构。本篇将着重介绍 V8 的语法解析过程。原视频上一篇是产品经理思维;本篇则是理工科思维;语法解析阶段对于前端来说尤其重要,相对 Noder 来说较弱,因为 parser 只会影响应用启动和前期的运行阶段。对于前端同学来说,经常习惯性的引入一些很大的库,而只使用了其中1,2个函数。例如 lodash。这样对性能的影响到底有多大? 还是结论先行 V8的语法解析有2种模式:eager 解析器(全面)和 lazy 预解析器(快速)。虽然 lazy 解析比 eager 快一倍,但是lazy可能导致需要1.5倍的解析时间;(lazy 预解析后,还需要 eager 解析一次)。你可以用Optimize.js强制 eager 运行 JavaScript 的语法解析速度为:1MB/S。解析400k JavaSc
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- 设置Eclipse缩进为4个空格,增强代码规范
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Windows10,CentOS7,CentOS8安装Nodejs环境
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果