Redis 连接池被占满(泄漏)问题排查

目录

一、现象

如题,导致所有请求都10s后报500错误,查询日志,大量报错org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is org.springframework.data.redis.connection.PoolException: Could not get a resource from the pool; nested exception is java.util.NoSuchElementException: Timeout waiting for idle object"

二、核心原因及解决方案

原因1:连接池配置过小,无法满足并发需求

这是最常见原因,并发请求数超过连接池最大连接数且连接未及时归还,导致连接池耗尽。

解决方案:调整Spring Boot连接池配置(application.yml)

yaml 复制代码
spring:
  redis:
    # Redis基础配置
    host: 127.0.0.1
    port: 6379
    password: your_password # 无密码则注释
    database: 0
    timeout: 5000ms # 连接超时时间(默认2000ms,可适当延长)
    # Lettuce连接池配置(Jedis配置类似,替换lettuce为jedis即可)
    lettuce:
      pool:
        max-active: 200    # 最大活跃连接数(默认8,按业务峰值调整)
        max-idle: 50       # 最大空闲连接数
        min-idle: 10       # 最小空闲连接数
        max-wait: 3000ms   # 获取连接最大等待时间(默认-1无限等待,建议设置)
      shutdown-timeout: 100ms # 连接关闭超时时间

原因2:连接泄漏(连接未释放)

代码中获取连接后未正确关闭,导致连接长期占用,最终耗尽连接池。

检查&修复方法:

  1. 优先使用Spring管理的RedisTemplate,避免手动创建连接;
  2. 若手动操作Jedis连接,必须在finally块释放:
java 复制代码
@Autowired
private JedisPool jedisPool;

public void redisOperation() {
    Jedis jedis = null;
    try {
        jedis = jedisPool.getResource();
        // 执行Redis操作
        jedis.set("key", "value");
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (jedis != null) {
            jedis.close(); // 关键:释放连接回池
        }
    }
}

原因3:Redis服务/网络不可用

Redis宕机、防火墙拦截、网络延迟过高,导致连接池连接失效且无法创建新连接。

排查步骤:

  1. 测试连通性:redis-cli -h {host} -p {port} ping(正常返回PONG);
  2. 检查Redis服务状态:systemctl status redis(Linux);
  3. 查看Redis日志:/var/log/redis/redis-server.log(默认路径);
  4. 测试网络:telnet {host} 6379ping {host}

原因4:超时参数配置不合理

Redis操作耗时过长或连接超时参数过短,导致连接无法回收。

优化: 在上述YAML配置中调整timeout(连接超时)和max-wait(等待连接超时)参数。

三、关键监控手段(定位连接异常)

1. 监控Redis Established连接数

established是TCP层面连接状态,用于快速排查连接数是否异常:

bash 复制代码
# 方法1:netstat(统计6379端口ESTABLISHED连接数)
netstat -an | grep 6379 | grep ESTABLISHED | wc -l
# 详细输出(含客户端IP/端口)
netstat -antp | grep 6379 | grep ESTABLISHED

# 方法2:ss(更高效,按IP分组统计连接数)
ss -an | grep 6379 | grep ESTAB | wc -l
ss -an | grep 6379 | grep ESTAB | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr

# 方法3:Redis内置命令(精准,排除非Redis连接)
redis-cli INFO clients
# 核心字段:connected_clients(当前客户端连接数)、blocked_clients(阻塞连接数)

2. 执行CLIENT LIST命令(精准定位异常连接)

该命令列出所有连接的详细信息,是排查连接泄漏/并发过高的核心:

bash 复制代码
# 基础执行(本地Redis)
redis-cli CLIENT LIST
# 远程Redis执行
redis-cli -h 192.168.1.100 -p 6379 -a your_password CLIENT LIST

# 筛选异常连接(示例)
# 1. 空闲超300秒的连接(疑似泄漏)
redis-cli CLIENT LIST | grep -E "idle=[3-9][0-9]{2}|idle=[1-9][0-9]{3,}"
# 2. 特定IP的连接
redis-cli CLIENT LIST | grep "192.168.1.200"
# 3. 按IP统计连接数
redis-cli CLIENT LIST | awk -F'[ =]' '{print $4}' | cut -d: -f1 | sort | uniq -c | sort -nr
CLIENT LIST核心字段解读(泄漏特征)
字段 含义 排查重点
id 连接ID 唯一标识连接
addr 客户端IP:端口 定位异常连接的来源服务器
age 连接建立时长(秒) 数值过大说明连接长期未释放
idle 连接空闲时长(秒) idle接近age:连接建立后未使用(泄漏);idle过小:连接持续被占用(并发高)
cmd 最后执行的命令 定位耗时操作(如大key的GET/SET)

泄漏特征:如果发现大量连接 age 值非常大(比如几天甚至几周),但同时 idle 值也非常大,这些很可能就是泄漏的连接------它们很早就被创建,但长期闲置没有被归还到池中。

进阶:关闭异常连接
bash 复制代码
# 按连接ID关闭
redis-cli CLIENT KILL 1234
# 按IP:端口关闭
redis-cli CLIENT KILL 192.168.1.200:54321
# 批量关闭空闲超300秒的连接
redis-cli CLIENT LIST | awk -F'[ =]' '{if($18>300) print "CLIENT KILL "$4}' | redis-cli

四、排查流程总结

  1. 先用redis-cli INFO clients查看connected_clients是否接近连接池max-active,确认连接池是否耗尽;
  2. ss/CLIENT LIST统计应用服务器连接数,区分是"并发过高"(idle小)还是"连接泄漏"(idle接近age);
  3. 查看CLIENT LISTcmd字段,定位慢查询或耗时长的操作;
  4. 针对性调整:并发高则调大连接池参数,连接泄漏则修复代码释放逻辑,网络/服务问题则排查Redis服务和网络。

关键点回顾

  1. 核心问题是Redis连接池无可用连接,优先检查max-active/max-wait等连接池配置;
  2. 连接泄漏是高频诱因,务必确保所有Redis连接使用后正确释放;
  3. INFO clientsCLIENT LIST是定位异常连接的核心命令,可快速区分并发过高/连接泄漏/服务不可用等根因。
相关推荐
亲爱的非洲野猪几秒前
从ReentrantLock到AQS:深入解析Java并发锁的实现哲学
java·开发语言
wheelmouse77882 分钟前
如何设置VSCode打开文件Tab页签换行
java·python
yangminlei4 分钟前
Spring Boot——日志介绍和配置
java·spring boot
廋到被风吹走11 分钟前
【Spring】Spring Boot Starter设计:公司级监控SDK实战指南
java·spring boot·spring
QQ_43766431414 分钟前
redis相关命令讲解及原理
数据库·redis·缓存
码头整点薯条16 分钟前
启动报错:Invalid value type for attribute ‘factoryBeanObjectType‘ 解决方案
java
沛沛老爹16 分钟前
Web开发者进阶AI:Agent Skills-深度迭代处理架构——从递归函数到智能决策引擎
java·开发语言·人工智能·科技·架构·企业开发·发展趋势
工具罗某人19 分钟前
docker快速部署kafka
java·nginx·docker
秋饼21 分钟前
【手撕 @EnableAsync:揭秘 SpringBoot @Enable 注解的魔法开关】
java·spring boot·后端
Good_Starry24 分钟前
Java——正则表达式
java·开发语言·正则表达式