生产上通过scan命令,查询一个大key耗时40s后,报 Could not get a resource from the pool,初步报错是连接池的连接数不够,从网上搜了一些解决方案。
排查过程:
 一、首先需要先尝试连接redis,如果连接不上那就重启
 二、看redis的配置文件结合自己的需求看是否需要扩大配置,比例最大连接数等
 三、连接redis,查看当前已连接数和配置
 进入redis:./redis-cli -h 127.0.0.1 -p 6379 -a passwd
 查看连接数:info clients
(其中connected_client的数量就是已连接数,和配置文件中的最大连接数作比较,如果connected_client的数量没有超过最大连接数建议看下redis的配置文件中地址或者密码是否填写错误)
 查看最大连接数:config get maxclients
 (如果connected_client的数量大约最大连接数就需要用下面命令进行查看)
 查看所有连接:client list
其中查看所有连接的展示的列表内容我在下方标出,注意看下idle这个字段,代表的空闲时间,单位是秒,这时可以看到idle的时间非常长,所以我这边确定程序获取获取大量的redis连接资源并且没有释放。(client list命令的属性名称及解释放在文章末尾,需要自取)
四、重启服务
 重启其中一个服务后这边再调用info clients连接数从1400掉到了600,后台也不会再报这样子的错误了,但是这并没有解决问题只是单纯的缓和了一下,如果程序继续运行下去还是会出现这样子的问题
五、查看自己所使用的redis的工具类
 查看封装或者使用的是redisTemplate还是Jedis。如果是jedis需要注意的是jedis需要手动释放资源,当时jdk7之后应该有优化,我这边上网查了一下具体区别如下:
Jedis:
 一般情况下,我们在使用完连接资源后都要 close 关闭连接,释放资源。这么常用的方法,基于习惯,Java 在 jdk1.7 之后为我们提供了一个很好的方法
 try-with-resources Statement ,我们不再需要手动调用 close 方法,也可以释放连接。
 此处以 Jedis 为例子,说下该方法的使用,如果我们的 Jedis 是通过 jedisPool.getResource() 从连接池获取的话,调用 close 方法将会把连接归还到连接池。否则,断开与 Redis 的连接。
 try-with-resources Statement
 使用 try-with-resources Statement " try(resource) ",它会自动关闭括号内的资源(resources),不用手动添加代码 xx.close();
 实际上是有一个隐式 finally 中调用了 resource.close();关闭了资源。
 使用这个方法前提是,resource 必须继承自 java.lang.AutoCloseable
 不单 Jedis 可用,InputStream,OutputStream 等也可用,只要继承了 AutoCloseable
SpringDataRedis:
 相对于Jedis来说可以方便地更换Redis的Java客户端,比Jedis多了自动管理连接池的特性,方便与其他Spring框架进行搭配使用如:SpringCache,当然性能方面肯定是不如原生的好。
 需要注意的是redisTemplate使用的是自动管理连接池,按道理来说调用完之后会自动释放连接,但是当redis开启了事务的时候,就需要手动释放连接,所以解决方案有两种
 RedisTemplate配置enableTransactionSupport为true(开启事务)时,连接不会自动释放,解决方案:
 1.找到spring对于redis的配置文件,将enableTransactionSupport设置为false(关闭事务)
 2.RedisTemplate操作后加入手动释放代码
 RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
文章末尾
 client list命令属性详解摘自redis官网(https://www.redis.net.cn/order/3657.html)
 Redis Client List 命令用于返回所有连接到服务器的客户端信息和统计数据。
语法
 redis Client List 命令基本语法如下:
redis 127.0.0.1:6379> CLIENT LIST
 可用版本 大于等于 2.4.0
返回值
 命令返回多行字符串,这些字符串按以下形式被格式化:
每个已连接客户端对应一行(以 LF 分割)
 每行字符串由一系列 属性=值 形式的域组成,每个域之间以空格分开
 以下是域的含义:
addr : 客户端的地址和端口
 fd : 套接字所使用的文件描述符
 age : 以秒计算的已连接时长
 idle : 以秒计算的空闲时长
 flags : 客户端 flag
 db : 该客户端正在使用的数据库 ID
 sub : 已订阅频道的数量
 psub : 已订阅模式的数量
 multi : 在事务中被执行的命令数量
 qbuf : 查询缓冲区的长度(字节为单位, 0 表示没有分配查询缓冲区)
 qbuf-free : 查询缓冲区剩余空间的长度(字节为单位, 0 表示没有剩余空间)
 obl : 输出缓冲区的长度(字节为单位, 0 表示没有分配输出缓冲区)
 oll : 输出列表包含的对象数量(当输出缓冲区没有剩余空间时,命令回复会以字符串对象的形式被入队到这个队列里)
 omem : 输出缓冲区和输出列表占用的内存总量
 events : 文件描述符事件
 cmd : 最近一次执行的命令
 客户端 flag 可以由以下部分组成:
O : 客户端是 MONITOR 模式下的附属节点(slave)
 S : 客户端是一般模式下(normal)的附属节点
 M : 客户端是主节点(master)
 x : 客户端正在执行事务
 b : 客户端正在等待阻塞事件
 i : 客户端正在等待 VM I/O 操作(已废弃)
 d : 一个受监视(watched)的键已被修改, EXEC 命令将失败
 c : 在将回复完整地写出之后,关闭链接
 u : 客户端未被阻塞(unblocked)
 A : 尽可能快地关闭连接
 N : 未设置任何 flag
 文件描述符事件可以是:
r : 客户端套接字(在事件 loop 中)是可读的(readable)
 w : 客户端套接字(在事件 loop 中)是可写的(writeable)
 原文链接:https://blog.csdn.net/weixin_43609618/article/details/123502733