共计 1311 个字符,预计需要花费 4 分钟才能阅读完成。
问题
运维反应 redis 客户端连接数太多,超过默认最大限制 1W。
执行命令
./redis-cli –h host –p port info clients
查看 redis 客户端连接数,共 6 个节点每个节点都是 2000+
分析
执行命令
./redis-cli –h host –p port client list
查看具体连接信息,有大量空闲连接,主节点大量 cmd=null,从节点大量 cmd=readonly,且 idle 时间和 age 时间差不多大的连接
说明大部分连接都是没有用到的。
发现 Jedis 连接池的 minEvictableIdleTimeMillis 和timeBetweenEvictionRunsMillis都配置成了 -1,是不是 Jedis 连接池未及时回收连接的问题呢?但 maxTotal 配置的是 20,一共 30+ 个组件,不应该超过这个值啊!
写个脚本,先用 jps 查看组件 pid,再
netstat –tanlp | grep pid | wc -l
统计每个组件的连接,发现每个组件都已经十倍超出这个值,平均 200+。
打断点进入 Jedis 连接池中实现空闲连接检测的 GenericObjectPool.evict()方法,发现 IdleObjects 一直是 0,并没有需要丢弃的空闲连接。
基于对 commons-pool2 的信任,而且同个组件的 druid 连接池并没有出问题(两者用的都是用 commons-pool2 实现自己的连接池),我觉得问题应该出现在其他地方。
打开 java 进程的 jmx 功能(或者使用 idea 的 remote 远程调试功能),进一步分析,配置如下(看 key 就能明白作用):
-Djava.rmi.server.hostname=IP
-Dcom.sun.management.jmxremote.port=Port
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
用 jvisualvm 连接目标组件,发现 commons-pool-evictor-thread 线程在空闲着
可以确定 Jedis 连接池并没有多余的连接需要丢弃。
一顿分析,再重新看一次,发现有很多 redisson-netty 开头的线程一直在运行
框架中确实使用了 redisson,而且大部分配置项都是用的默认值,打个断点,SpringContextUtil.getBean(RedissonClient.class)获取 RedissonClient 到处看看,发现!
connectionManager 下面的 connectionWatcher 记录了使用到的 Redis 连接!
太多了,而且 lastUsageTime 都是组件刚启动的时候,说明并没有使用过!而且 6 个节点每个 32 个连接,再加上 Pubsub 连接的数量和 Jedis 连接池的数量,正好和统计出来的数量差不多!
解决方案
问题应该就在这里,将 Redisson 的 SlaveConnectionMinimumIdleSize 和 MasterConnectionMinimumIdleSize 设置成 1,重启组件再对比一下连接数
O~K~
还是配置的坑啊 – -!