发现问题
在使用Cacheable注解的时候,为了解决并发查的问题,使用了sync=true,但是出现了下面的问题:
导致整个服务都不可用了。
分析问题
spring-data-redis的版本为1.8.12.RELEASE
初步怀疑是不是线程卡住了,使用jstack命令,输出日志:
从日志可以看出是redis的操作被什么锁住了,从日志的类一步一步看出,终于看到了真凶。接下来让我们一步一步来看:
找到RedisTemplate类,定位到
这个方法会找到RedisCache
类下的AbstractRedisCacheCallback
类,
这个方法的具体代码如下:
protected boolean waitForLock(RedisConnection connection) {
boolean retry;
boolean foundLock = false;
do {
retry = false;
//判断是否存在具体key~lock,如果存在,那么休眠300毫秒,
if (connection.exists(cacheMetadata.getCacheLockKey())) {
foundLock = true;
try {
Thread.sleep(WAIT_FOR_LOCK_TIMEOUT);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
retry = true;
}
} while (retry);
return foundLock;
}
此时这个线程就一直在等待,等这个key失效,但是这个key在redis中的永久有效的,所以就进入死循环了。
这个AbstractRedisCacheCallback
类有以下几个子类,
但是只有RedisWriteThroughCallback
类调用了unlock方法,
其他几个类就没有调用unlock方法
如果在调用过程中,服务重启或者出现假死,那么unlock没有执行到,就会出现服务无响应的问题。
解决问题
可以写个定时任务,每隔几分钟扫一下redis,如果出现该key就进行删除,需要判断一定时间内都存在的情况才能删除,防止误删。
本文为博主原创文章,未经博主允许不得转载。
更多内容请访问:IT源点
注意:本文归作者所有,未经作者允许,不得转载