You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 23:34:59