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

相关推荐
weixin_3077791312 分钟前
C#程序实现将Teradata的存储过程转换为Snowflake的sql的存储过程
数据库·数据仓库·c#·云计算·迁移学习
李高钢12 分钟前
c#获取当前程序所在目录避坑
开发语言·数据库·c#
金仓拾光集38 分钟前
金仓数据库践行社会责任:以技术驱动绿色计算与数据普惠
运维·数据库·oracle·kingbase·数据库平替用金仓·金仓数据库
金仓拾光集1 小时前
金仓数据库赋能地铁AFC系统升级:核心技术实现与落地
运维·数据库·ux·kingbase·kingbasees·数据库平替用金仓·金仓数据库
Wang's Blog1 小时前
Linux小课堂: Squid代理缓存服务器部署与访问控制实战指南
linux·服务器·缓存
2503_928411562 小时前
10.31 MySQL数据记录操作
数据库·sql·mysql
CryptoRzz2 小时前
印度实时股票数据源接口对接文档-IPO新股、k线数据
java·开发语言·数据库·区块链
码农阿豪3 小时前
平滑过渡,破解多库并存:浙人医基于金仓KFS的医疗信创实战解析
数据库·kingbasees
埃泽漫笔3 小时前
Redis哨兵与集群模式
redis
自由日记3 小时前
mysql初修1
数据库·mysql