jmeter压测发现redis无法获取到连接

最近使用jmeter压测了一下网站首页,发现流量上来之后,过了一会,整个网站就不能打开了,白页。然后就登录sentry日志平台查看异常,发现有几千个jedis相关的异常

异常信息:获取不到redis链接

Spring Boot版本:2.0.8.RELEASE

jedis: 2.9.0

commons-pool2: 2.2

[http-nio-8017-exec-515] - get异常
org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisException: Could not get a resource from the pool
    at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:286)
Caused by: java.util.NoSuchElementException: Timeout waiting for idle object

jstack

然后就尝试使用jstack抓一下JVM线程堆栈,看看JVM在忙什么。ssh远程登录到服务器,然后使用jps -l来查看java进程,定位到进程pid

[root@xxxbt02 current]# jstack 15782 > ec-04.txt

通过观察jstack发现有很多业务线程接近200个在超时等待redis连接。顺便抓一下内存dump文件。

jmap

[root@xxxbt02 current]# jmap -dump:format=b,file=ec-jmap-01.hprof 15782
Dumping heap to /opt/xxx/xxx-order-api/current/ec-jmap-01.hprof ...
Heap dump file created
[root@xxxbt02 current]# 

结论

通过分析jstack堆栈发现,大量线程在尝试获取redis连接,因为配置了最大等待时间2s, 在2s后获取不到连接,导致抛出异常RedisConnectionFailureException。然后线程任务结束。这就证明在2s内已始终获取不到redis连接。由于程序没有兜底方案,所以整个JVM中的服务不可用。应该是redis连接池中始终无可用连接。那应该就是默认的8个连接全部被占用了,没有被释放。最后通过Jedis GitHub源码库也验证了这个问题。原文地址:JedisPool exhausted in Jedis 2.10.0,根据异常表现,线程堆栈及相关源码,确实验证了这一点:连接池中的8个连接被耗尽了,没有返还到池中。所以后来的线程任务一直拿不到redis连接。接着将jedis版本升级到2.10.2,再次测试发现问题修复了。后来也督促项目组对相关代码做了优化,减少redis访问次数,增加兜底方案,增加guava本地缓存,同时将jedis换成lettuce。

参考资料

  • 记一次 Redis 连接池泄漏问题排查
  • JedisPool资源池优化
  • 使用redisTemplate高并发下连接池满的问题
  • redis连接未释放,导致redis连接池满,从而应用服务不可用的问题定位和解决
  • 由Redis客户端连接数大小说开去
  • 彻底解决 Jedis 连接池 获取不到连接,连接放回连接池错误的问题
  • Jedis连接池满相关解决方案
  • seaweedfs文件存储服务器搭建

你可能感兴趣的:(jmeter压测发现redis无法获取到连接)