使用Lettuce-mod 3.6.0创建GenericObjectPool异常,请求协助排查
问题:Lettuce-mod 3.6.0 结合 Commons-Pool2 2.11.1 连接池无法正常工作
环境与实现步骤
使用Lettuce-mod 3.6.0和commons-pool2 2.11.1版本,按以下步骤创建Redis客户端与连接池:
创建Redis客户端
this.client = RedisModulesClient.create(redisURI);
创建连接池(参照Lettucemod官方文档)
GenericObjectPoolConfig<StatefulRedisModulesConnection<String, String>> config = new GenericObjectPoolConfig<>(); config.setMaxTotal(20); this.pool = ConnectionPoolSupport.createGenericObjectPool(() -> this.client.connect(), config);
异常现象
连接池创建后未正常工作,打印this.pool变量得到如下信息:
this.pool = [maxTotal=20, blockWhenExhausted=true, maxWaitDuration=PT-0.001S, lifo=true, fairness=false, testOnCreate=false, testOnBorrow=false, testOnReturn=false, testWhileIdle=false, durationBetweenEvictionRuns=PT-0.001S, numTestsPerEvictionRun=3, minEvictableIdleTimeDuration=PT30M, softMinEvictableIdleTimeDuration=PT-0.001S, evictionPolicy=org.apache.commons.pool2.impl.DefaultEvictionPolicy@cf649db, closeLock=java.lang.Object@cf79f21, closed=false, evictionLock=java.lang.Object@cf79f23, evictor=null, evictionIterator=null, factoryClassLoader=java.lang.ref.WeakReference@cf64a1b, oname=org.apache.commons.pool2:type=GenericObjectPool,name=pool6, creationStackTrace=java.lang.Exception at org.apache.commons.pool2.impl.BaseGenericObjectPool.<init>(BaseGenericObjectPool.java:407) at org.apache.commons.pool2.impl.GenericObjectPool.<init>(GenericObjectPool.java:147) at io.lettuce.core.support.ConnectionPoolSupport$1.<init>(ConnectionPoolSupport.java:117) at io.lettuce.core.support.ConnectionPoolSupport.createGenericObjectPool(ConnectionPoolSupport.java:117) at io.lettuce.core.support.ConnectionPoolSupport.createGenericObjectPool(ConnectionPoolSupport.java:94) at com.ventusproxy.proxy.cluster.storages.RedisClusterImpl.createPool(RedisClusterImpl.java:155) at com.ventusproxy.proxy.cluster.storages.RedisClusterImpl.startup(RedisClusterImpl.java:99) at com.ventusproxy.proxy.cluster.storages.RedisClusterImpl.start(RedisClusterImpl.java:44) at com.ventusproxy.proxy.services.storage.StorageService.addStorage(StorageService.java:50) at com.ventusproxy.proxy.services.storage.StorageService.startup(StorageService.java:35) at com.ventusproxy.proxy.servlet.data.GlobalData.startPrimaryServices(GlobalData.java:279) at com.ventusproxy.proxy.servlet.data.GlobalData.startVentus(GlobalData.java:175) at com.ventusproxy.proxy.servlet.data.GlobalData.start(GlobalData.java:108) at com.ventusproxy.proxy.servlet.AsyncProxyServlet.init(AsyncProxyServlet.java:40) at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1173) at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1118) at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1011) at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4953) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5267) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1427) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1417) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:887) , borrowedCount=0, returnedCount=0, createdCount=0, destroyedCount=0, destroyedByEvictorCount=0, destroyedByBorrowValidationCount=0, activeTimes=StatsStore [[]], size=100, index=0], idleTimes=StatsStore [[]], size=100, index=0], waitTimes=StatsStore [[]], size=100, index=0], maxBorrowWaitDuration=PT0S, swallowedExceptionListener=null, factoryType=null, maxIdle=10, minIdle=5, factory=RedisPooledObjectFactory [], allObjects={}, createCount=0, idleObjects=[], abandonedConfig=null]
目前已尝试更换不同版本commons-pool2,但问题依然存在,缺少有效错误信息无法定位问题,请求排查思路与解决方案。
排查思路与解决方案
1. 修复连接池的无效配置参数
从打印的池信息中能看到两个明显异常的参数:
maxWaitDuration=PT-0.001S:等待时长为负数,会导致线程获取连接时直接抛出异常,不会进入等待逻辑durationBetweenEvictionRuns=PT-0.001S:驱逐线程运行间隔为负数,属于无效配置
建议显式设置这两个参数为合理正数:
config.setMaxWaitDuration(Duration.ofSeconds(3)); // 设置获取连接的最大等待时间为3秒 config.setDurationBetweenEvictionRuns(Duration.ofMinutes(1)); // 设置驱逐线程每分钟运行一次
2. 单独验证Redis连接是否能正常建立
池的createdCount=0说明从未成功创建过连接,先脱离连接池验证基础连接:
- 编写测试代码,直接调用
this.client.connect(),然后执行PING命令,检查是否能正常响应 - 确认Redis URI的正确性:主机、端口、认证密码(如果有)、数据库编号等信息是否无误
- 排查网络连通性:确保应用服务器能访问Redis端口,无防火墙或安全组拦截
3. 开启连接池的测试参数捕获异常
当前配置testOnCreate=false、testOnBorrow=false,无法在连接创建/获取阶段暴露异常。临时开启这些参数:
config.setTestOnCreate(true); // 创建连接时自动测试可用性 config.setTestOnBorrow(true); // 获取连接时自动测试可用性
开启后若连接创建失败,池会直接抛出具体异常(如认证失败、连接超时),便于定位问题。
4. 检查连接池的实际使用逻辑
确认代码中是否正确调用了连接池的获取/归还方法:
- 获取连接:
StatefulRedisModulesConnection<String, String> conn = pool.borrowObject(); - 使用完毕必须归还,建议用try-with-resources语法确保自动归还:
try (StatefulRedisModulesConnection<String, String> conn = pool.borrowObject()) { RedisCommands<String, String> commands = conn.sync(); String pingResult = commands.ping(); // 执行其他Redis操作 } catch (Exception e) { // 处理异常 }
如果从未调用borrowObject(),池的borrowedCount自然为0,会呈现"未工作"的状态。
5. 开启日志调试查看详细流程
开启Lettuce和Commons-Pool2的DEBUG日志,查看连接创建和池操作的详细过程:
- 以Logback为例,添加日志配置:
<logger name="io.lettuce" level="DEBUG"/> <logger name="org.apache.commons.pool2" level="DEBUG"/>
日志中会包含连接建立的细节、池内部的状态变化,能帮助发现隐藏的异常。
内容的提问来源于stack exchange,提问作者JBalaguero
相关产品推荐
相关产品推荐

