Redis遇到过的问题 (Could not get a resource from the pool )

生产上通过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

相关推荐
dazhong20121 小时前
PLSQL 客户端连接 Oracle 数据库配置
数据库·oracle
了一li3 小时前
Qt中的QProcess与Boost.Interprocess:实现多进程编程
服务器·数据库·qt
码农君莫笑4 小时前
信管通低代码信息管理系统应用平台
linux·数据库·windows·低代码·c#·.net·visual studio
别致的影分身4 小时前
使用C语言连接MySQL
数据库·mysql
京东零售技术6 小时前
“慢”增长时代的企业数据体系建设:超越数据中台
数据库
sdaxue.com6 小时前
帝国CMS:如何去掉帝国CMS登录界面的认证码登录
数据库·github·网站·帝国cms·认证码
o(╥﹏╥)7 小时前
linux(ubuntu )卡死怎么强制重启
linux·数据库·ubuntu·系统安全
海海不掉头发7 小时前
苍穹外卖-day05redis 缓存的学习
学习·缓存
阿里嘎多学长7 小时前
docker怎么部署高斯数据库
运维·数据库·docker·容器
Yuan_o_7 小时前
Linux 基本使用和程序部署
java·linux·运维·服务器·数据库·后端