Jedis连接RedisGraph间歇性报Read timed out异常问题咨询
问题根因定位方向
- 连接泄漏是首要排查方向:你压测复现不了很正常——压测是持续打满流量,连接会被反复复用,不会出现长期占用不释放的情况;线上流量有波峰波谷,只要代码里存在异常分支没归还连接、或者RedisGraph返回异常时客户端没走释放连接的逻辑,坏连接/被占用的连接就会慢慢积累,一周左右攒到占满连接池,后续拿到的都是半开死连接,发请求就会触发读超时。你之前把最大连接数调到160,本质上只是拉长了坏连接攒满的周期,刚好对应你一周左右复现的时间规律,解决不了根本问题。
- RedisGraph慢查询堆积:你现在用的无参query接口没设置单查询超时,当前写的MATCH两个节点再建边的Cypher,如果没建索引,本质是做全图笛卡尔积匹配;线上数据跑一周后节点、边的规模涨上来,单查询执行时间很容易超过你设的60s socket超时。而且Redis是单线程处理命令,一个慢查询堵着,后面所有请求都要排队,等排到的时候早就过了socket超时时间,就会抛异常。压测环境一般不会灌和线上同规模的数据集,所以跑再大流量也触发不了这个问题。
- 空闲连接被静默回收:你现在redis.conf里
timeout设的0(服务端永不主动断开空闲连接),tcp-keepalive是300s,但代码里soTimeout设的60s,再叠加Docker网络栈、ECS安全组、VPC网关普遍存在的300-900s空闲连接回收策略,只要连接闲置超过网关阈值就会被静默掐断,客户端连接池感知不到,还把这些死连接当可用连接存着,等业务拿这些死连接发请求,就会等满超时时间抛异常。系统运行时间越长,池子里攒的死连接越多,出问题的概率就越高,重启后连接池重建、死连接清空自然就恢复了。 - Jedis 3.5.1版本已知缺陷:这个版本的Jedis连接池默认不会在借出连接时做可用性校验,也不会在请求异常后自动把坏连接从池里剔除,死连接会反复被借给业务线程用,很容易出现连续超时的问题。
可落地解决方案
- 连接池配置修正
- 开启借出连接时的可用性校验,设置
testOnBorrow=true,用PING命令做探活,拿到连接先确认存活再给业务用,避免拿到死连接 - 开启空闲连接自动回收,设置
minEvictableIdleTimeMillis=300000(闲置5分钟的连接主动回收)、timeBetweenEvictionRunsMillis=60000(每1分钟扫描一次空闲连接),不要把长期闲置的连接留在池子里 - 不要盲目调大最大连接数,Redis是单线程处理命令,连接数超过CPU核数*2只会增加上下文切换开销,建议先把
maxTotal改回64;同时开启连接泄漏检测:设置removeAbandoned=true、removeAbandonedTimeout=120,自动回收占用超过2分钟没归还的连接,打开泄漏日志就能直接定位到没释放连接的代码位置
- 开启借出连接时的可用性校验,设置
- RedisGraph查询优化
- 先给查询用到的属性建索引,避免全图扫描:
CREATE INDEX FOR (ag:dGrp) ON (ag.v); CREATE INDEX FOR (pg:resUGrp) ON (pg.v);
- 替换现有字符串拼接的Cypher写法,改用参数化传参+MERGE逻辑,一方面避免注入风险,另一方面RedisGraph可以缓存执行计划降低耗时,同时避免重复建边:
MATCH (ag:dGrp{v:$docGroupId}),(pg:resUGrp{v:$userGroupId}) MERGE (pg)-[r:dgE]->(ag) SET r.ppv = $ppv, r[$identifierFlag] = 1
- 所有query调用改用带超时参数的重载方法,设置单查询超时为10s,避免慢查询拖垮整个实例:
// timeout参数单位为毫秒 api.query("你的业务图名", cypher, 10000);
- 网络参数对齐
- 把redis.conf里的
timeout参数从0改成300,让服务端主动回收闲置超过5分钟的连接,和客户端、VPC网关的空闲超时阈值保持一致 - 不要手动调用
setSoTimeout,把socket超时统一交给Jedis连接池配置,设置soTimeout=30000(30s),和查询超时、服务端超时对齐 - Docker启动Redis容器时添加
--sysctl net.ipv4.tcp_keepalive_time=120参数,把内核层的TCP keepalive探测间隔改成2分钟,比所有中间件的空闲超时短,提前探测并释放死连接
- 把redis.conf里的
- 版本升级:把Jedis版本升级到3.8.0以上,或者直接升级到4.x稳定版,修复3.5.1版本中连接池不剔除坏连接、异常处理逻辑缺失的已知bug
验证方法:改完配置后持续监控连接池指标(活跃连接数、空闲连接数、等待连接的线程数)和RedisGraph慢日志,如果活跃连接数长期不回落,就说明还存在连接泄漏,通过泄漏检测日志就能定位到具体代码点。
内容的提问来源于stack exchange,提问作者Atharv Thakur
相关产品推荐
相关产品推荐

