记录一次并发情况下的redis导致服务假死的问题解决
作者:简单简单小白
问题描述
最近项目在做性能压测,框架使用的是 spring boot 2.1.2 + jedis 2.9.1,80个并发持续压测4-5分钟服务就假死,所有的请求就pending,查看服务日志没有任何异常,查看其它没有使用redis的接口都能正常请求。
查找问题思路
查看了一下redis的连接配置,都是正常够用的
再使用jstack看一下堆栈信息
发现很多WAITING的线程,再往下看都是redis的getResource方法导致的等待。
查看redis的源码
Jedis.java
@Override public void close() { if (dataSource != null) {//1 if (client.isBroken()) { this.dataSource.returnBrokenResource(this); } else { this.dataSource. returnResource(this); // 2 } this.dataSource = null; // 3 } else { super.close(); } }
分析一下这个代码,
client.isBroken()
这里默认值是false,连接释放的时候先释放resource 然后再将dataSource置为null,那如果是并发的情况下话,那有可能再下一个线程进来的时候dataSource已经就是null了,在执行第2步的时候dataSource刚好被置为null,那这个时候就无法释放连接了。这个时候我们再看下获取连接的方法。JedisSentinelPool.java
@Override public Jedis getResource() { while (true) { Jedis jedis = super.getResource(); jedis.setDataSource(this); // <-- This line // get a reference because it can change concurrently final HostAndPort master = currentHostMaster; final HostAndPort connection = new HostAndPort(jedis.getClient().getHost(), jedis.getClient() .getPort()); if (master.equals(connection)) { // connected to the correct master return jedis; } else { returnBrokenResource(jedis); } } }
这里
jedis.setDataSource(this);
设置的则为null。
问题解决方案
我查看了一下jedis的github,在issue上有找到有人曾经提出过这样的问题,https://github.com/redis/jedis/issues/1920
,给出的解决方案是升级jedis的jar包到2.10.2版本以上,换成高版本的以后问题果然就解决了。
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.10.2</version> </dependency>
这里要注意一下的是jedis的版本跟spring-data-redis的版本是有一个对应关系的。
spring-data-redis 2.1.x 对应的jedis版本是2.x.x 版本
spring-data-redis 2.2.x 对应的jedis 版本就是3.x版本了
分析升级版本以后的改动
还是看那两个类,看看新版本做了什么改动
public void close() { if (this.dataSource != null) { Pool<Jedis> pool = this.dataSource; this.dataSource = null; if (this.client.isBroken()) { pool.returnBrokenResource(this); } else { pool.returnResource(this); } } else { super.close(); } }
这里很明显的处理方式就是讲dataSource复制给pool,然后用pool去释放资源,这个时候设置dataSource与这个就没有关系了,就不存在释放资源释放不了的情况了。
到此这篇关于记录一次并发情况下的redis导致服务假死的问题解决的文章就介绍到这了,更多相关redis导致服务假死内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!