1、问题:
方法使用@Cacheable
注解,服务每次重启后,调到这个方法都服务停住
了,日志也不打了。
2、原因:
服务停止住了,发现redis会生成key~lock的锁,永不过期,也没有删除。
例如以下,在我们的key 后面加了~lock
3、解释:
在 Spring Framework 中,@Cacheable
注解用于缓存方法的返回结果。在使用 Redis 作为缓存存储时,你可能会看到以 key~lock
形式存在的键。这通常是为了实现缓存的并发控制和一致性而使用的。
具体来说,key~lock
是为了防止缓存击穿(cache breakdown)或缓存并发写入问题。以下是一些关键点:
-
缓存击穿和并发控制:
- 缓存击穿 指的是缓存中存储的数据过期了,导致多个线程同时去访问数据库,造成数据库压力过大。为避免这个问题,系统使用锁来确保只有一个线程能够去从数据源加载数据,而其他线程则等待数据加载完成。
- 并发控制 确保同一时间只有一个线程可以更新缓存数据。为了防止多个线程同时尝试加载数据到缓存中,系统会使用一个锁来确保数据的正确性和一致性。
-
key~lock
的作用:- 当一个线程第一次尝试从缓存中获取数据时,系统会在 Redis 中创建一个类似
key~lock
的临时锁键。 - 如果其他线程尝试获取相同的缓存数据,它们会看到这个锁,并且会等待锁释放,以避免同时触发多个数据加载操作。
- 一旦数据加载完成,锁会被删除,从而允许其他线程获取到缓存的数据。
- 当一个线程第一次尝试从缓存中获取数据时,系统会在 Redis 中创建一个类似
要查看 key~lock
的具体实现,你可以查看 Spring Cache 和 Redis 的相关源码:
- Spring Framework 源码:
@Cacheable
注解及其处理逻辑主要在org.springframework.cache.annotation
包下。- 缓存操作的实现可能涉及到
CacheInterceptor
类,该类负责拦截缓存操作。
该部分源码我没有找到,这段是GPT说明的,如果有同仁找到,麻烦评论告知下
5、说明:
我出现这个原因是我kill -9 服务的端口,服务直接停止,可能导致了这个key~lock还没删除掉,下次要进来读的时候,发现这个锁还在,就在等待。
-
锁未释放
:如果 Redis 锁没有被正确释放,下次启动时,服务可能会发现锁依然存在,从而无法进行缓存操作或者数据加载。 -
恢复机制
:为了避免这种情况,通常会在实现中设置锁的超时时间。这样即使服务崩溃,锁也会在超时后自动释放,允许其他服务继续获取缓存数据。 -
异常处理
:建议在服务中实现适当的异常处理和恢复机制,确保锁不会长时间存在,并尽可能恢复服务的正常运行。
6、建议:
1、服务不要直接kill 掉,可能会出现数据库或者redis事务还没处理完,导致出现一些事故
2、需要经常操作和获取redis缓存的,直接使用redisUtil.get(),直接获取就好,不要使用@Cacheable