Closed Charles5563 closed 3 months ago
你应该是本地缓存太多了,导致运行clean(加锁)的时间很长。
你一是缓存永久有效,二来估计没有指定localLimit,第三也不指定localExpire,jvm内存要爆了吧
你应该是本地缓存太多了,导致运行clean(加锁)的时间很长。
你一是缓存永久有效,二来估计没有指定localLimit,第三也不指定localExpire,jvm内存要爆了吧
非常感谢作者大神的回应. 下面是我的jetcache的配置,指定了本地的limit,数据量并不大
jetcache:
areaInCacheName: false
local:
default:
expireAfterAccessInMillis: 300000
expireAfterWriteInMillis: 600000
keyConvertor: fastjson2
limit: 100
type: linkedhashmap
remote:
default:
broadcastChannel: item-domain-query-service
keyConvertor: fastjson2
#mode: cluster
type: redis.lettuce
#异步获取结果的超时时间
asyncResultTimeoutInMillis: 6000
uri: redis://xxx
valueDecoder: kryo5
valueEncoder: kryo5
statIntervalMinutes: 1
跟踪程序发现本地缓存的配置如下图:
并且跟踪了崩溃前的jvm内存信息,没有发现任何异常
另外,从dump文件的对象集总数来看,对象占用空间不大
若是本地limit有效,也就是只有100个本地缓存数据,运行cleanExpiredEntry时间应该不会过长 监控这个清理动作是1分钟一次,这个运行时长超过一分钟,是否会导致写锁一直被占用? 从实际来看,应该不存在这种情形,请问还会存在哪些场景导致这个写锁没有释放呢? 谢谢.
另外补充信息: 当出现服务异常的时候,通过监控网关请求,发现请求量较少,不存在大并发的情况.
LRUMap是个非常简单的类,里面都是内存操作,你可以自己看。
从你的上面给的图来看,LRUMap占用18%应该是不正常的,这应该不是limit 100,你可以看看别的cache。yml里面指定的limit是可以被具体的cache覆盖的。
LRUMap是个非常简单的类,里面都是内存操作,你可以自己看。
从你的上面给的图来看,LRUMap占用18%应该是不正常的,这应该不是limit 100,你可以看看别的cache。yml里面指定的limit是可以被具体的cache覆盖的。
您好,感谢.
我们通过本地调试,确认这个本地缓存的数量是100,占用18%存储空间是因为单个存储对象数据量较大导致.
另外再补充服务异常时线程情况,确认是这个cleanExpiredEntry一直没有释放写锁
再补充一下监控cleanExpiredEntry方法的耗时情况(数据和测试环境一致):
该方法耗时几乎为0,不存在耗时长
这个写锁不释放的情况不好复现,并且一直也没有找到原因,且是在测试环境中时不时(有时一周出现一次,有时一两天就出现一次)出现导致服务不可用(线程资源占满,健康检查请求通不过),而生产环境暂时未出现过.比较两个环境的配置没有差异.比较担心生产环境是否会出现该问题,所以这几天都在排查,最后搜集到这些线索,依然找不到问题的根源.跟踪代码链路都没发现任何问题.
现在想到的解决办法是绕过这个cleanExpiredEntry,使用caffeine而不使用linkedhashmap,改动一下配置即可. 但是依然很想知道这个点出在哪个地方,是怎么回事.
请大佬跟踪一下.
LRUMap里面的锁是private的,只有它自己在用,所有的地方都是try finally释放的,不可能会没有释放。而且try里面都是内存操作没有堵塞。
我想到的可能:测试环境是不是谁打断点了。要不是内存占用太多,cleanExpiredEntry的时候gc卡了?
LRUMap里面的锁是private的,只有它自己在用,所有的地方都是try finally释放的,不可能会没有释放。而且try里面都是内存操作没有堵塞。
我想到的可能:测试环境是不是谁打断点了。要不是内存占用太多,cleanExpiredEntry的时候gc卡了?
我们也跟踪了这个读写锁,都是try finally的,都会被释放,所以跟踪代码完全看不到问题,而实际上却发现运行这个cleanExpiredEntry的线程处于就绪运行状态,其他获取数据的读锁都在等待写锁.
测试环境上面是不能进行本地远程调试的,没有打断点的可能性.至于说gc卡了,这个就不好说,忘记截图了,当时通过prometheus监控服务器的状态未发现问题,gc也很正常.
大佬,您觉得还有什么其他可能呢?
我看不出有什么问题,你需要排除一下其它原因。当然用caffeine也是很好的,性能肯定比我这个手撸的简单货强。
LinkedHashMapCache的意义在于,你不想引入额外依赖,大部分时候LinkedHashMapCache足够了。
我看不出有什么问题,你需要排除一下其它原因。当然用caffeine也是很好的,性能肯定比我这个手撸的简单货强。
LinkedHashMapCache的意义在于,你不想引入额外依赖,大部分时候LinkedHashMapCache足够了。
感谢大佬百忙中抽空看我提的这个,那我们就先用caffeine,谢谢
在清除本地缓存方法中,方法如下:
在这个h.getExpireTime()若是在redis当数据库使用数据永久有效的情况下,这个值为:
expireAfterWriteInMillis = CacheConsts.DEFAULT_EXPIRE 1000L;//即Integer.MAX_VALUE 1000L
几乎不存在本地缓存失效的情况.
具体跟踪代码如下:
![image](https://github.com/alibaba/jetcache/assets/24905964/0abf455d-eb2f-43a9-84b5-73832c13f594)
上面是本地缓存永久有效的逻辑,所以在这种场景下,是不需要清除本地缓存的. 但是在这个场景下,实际应用过程中,却发现这个写锁存在不释放的情况,导致读数据处于等待状态,使线程堆积导致服务异常. 服务日志如下: "http-nio-8080-exec-200" #1680 daemon prio=5 os_prio=0 tid=0x00007f6f8c0c3800 nid=0x6b9 waiting on condition [0x00007f6ce9bd8000] java.lang.Thread.State: WAITING (parking) at sun.misc.Unsafe.park(Native Method)
从应用程序的dump文件中,写锁的引用情况如下,可看出这个清除本地缓存的写锁没有释放,读锁排队
请问各位大佬们,这个问题是怎么回事,怎么解决?