1. 从一次线上告警说起:认识“Could not get a resource from the pool”
那天晚上,我正喝着咖啡,突然手机开始疯狂震动,监控大屏一片飘红。告警信息很明确:redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool。这个异常对于使用过Jedis的Java开发者来说,简直像“老朋友”一样熟悉,但每次出现都让人头疼。它直白地告诉你:你的应用无法从Redis连接池里拿到一个可用的连接了。
很多新手朋友一看到这个报错,第一反应就是:“连接池不够用了,赶紧把maxTotal调大!” 我刚开始也是这么想的,但踩过几次坑之后才发现,事情远没这么简单。盲目调大参数,就像给一个漏水的水桶不停地加水,不仅解决不了问题,还可能把整个系统拖垮。这个异常只是一个表象,背后可能藏着连接泄露、Redis服务端阻塞、网络问题、甚至是代码写法不当等多种原因。接下来,我就带你一层层剥开这个异常的外壳,看看里面到底藏着什么,并分享我这些年总结出来的实战解决方案。
简单来说,JedisPool就是一个管理Redis连接的工具箱。它基于Apache Commons Pool 2(核心类是GenericObjectPool)实现,帮你维护一定数量的Jedis连接对象。当你的业务代码需要操作Redis时,就从池子里“借”一个连接;用完了,再“还”回去。这样避免了每次操作都创建、销毁TCP连接的开销,极大地提升了性能。但是,如果“借”和“还”的环节出了问题,或者池子本身的大小设置不合理,这个工具箱就会罢工,抛出我们看到的异常。
2. 庖丁解牛:深入JedisPool与GenericObjectPoolConfig
要解决问题,得先懂原理。我们得钻进JedisPool和它底层的GenericObjectPool去看看。当你创建一个JedisPool时,核心是配置那个GenericObjectPoolConfig对象。这里面有一大堆参数,我挑几个最核心、最容易踩坑的给你详细讲讲。
首先,你必须理解这三个“铁三角”参数:
maxTotal:连接池里最多能同时存活的连接总数。这是你的“资源上限”。maxIdle:连接池里允许存在的最大空闲连接数。即使没有业务流量,池子也会保留这么多连接,以备不时之需。minIdle:连接池里至少要保证的空闲连接数。如果空闲连接少于这个数,池子会后台悄悄创建新的连接补上。
很多同学搞不清maxTotal和maxIdle的关系。我打个比方:maxTotal是你家客厅最多能容纳的客人总数(比如20人),maxIdle是客厅里常备的椅子数(比如15把)。平时客人不多,椅子够坐(空闲连接充足)。突然来了18个客人(并发请求),椅子不够了,你得临时从仓库搬3把出来(创建新连接),只要总人数不超过20就行。客人走后,如果客厅里椅子超过15把,多出来的就要收回去(销毁连接)。所以,最佳实践是设置 maxTotal = maxIdle,这样避免了连接数频繁伸缩带来的性能抖动。除非你的业务有明显的流量高峰和低谷,否则就这么设。
另一个至关重要的参数是maxWaitMillis(默认-1,表示永远等待)。 它控制了当连接池耗尽时,你的应用线程愿意等多长时间。如果设置为一个正数(比如5000毫秒),线程会阻塞等待这么久,期待有连接被归还;如果超时了还没等到,就会抛出我们开头的那个异常。我建议千万不要用默认值-1,否则在高并发下连接池耗尽时,所有线程都会无限制等待,导致服务完全僵死。设置一个合理的超时时间(如3-5秒),至少能让请求快速失败,给系统一个降级或告警的机会。
还有一组参数是关于连接健康检测的:testOnBorrow, testOnReturn, testWhileIdle。
testOnBorrow:每次从池子借连接时,是否执行一下ping命令检查连接是否有效。生产环境强烈建议设为false。因为每次借连接都ping一下,虽然安全,但多了一次网络往



被折叠的 条评论
为什么被折叠?



