使用 JFR 定位 Caffeine 同步缓存中的缺陷

本文讲述了如何使用JFR(Java Flight Recorder)来定位和分析一个基于Spring Boot + Cloud的微服务中,由于Caffeine同步缓存导致的HTTP请求超时问题。通过JFR收集的线程dump和源码分析,揭示了Caffeine同步缓存的机制缺陷,即在特定情况下,加载较慢的key会阻塞定时清理任务和其他线程。为了解决这个问题,文章建议改用异步缓存并提供了使用异步缓存时的注意事项。
摘要由CSDN通过智能技术生成

最近,某个 spring-boot + cloud 微服务并且基于 web-mvc 的同步微服务(也加入了异步响应式依赖 web-flux 用于局部敏感接口的非阻塞优化)的某一个实例出现问题,所有的 http 请求均超时。其他实例没有(剽窃可耻)出这个问题,这个问题实例触发了 k8s 健康检查失败,被重启。

由于这个事件发生在周末的时候,我们只能事后分析。事后分析的来源是 JFR,针对线上每个 JVM 进程,我们的启动配置是:

其中 disk=true 代表如果内存中 JFR 事件 buffer 满了会 dump 到本地文件,默认目录是 /tmp/进程启动时间以及进程号,其中的 .jfr 文件以开始时间命名。maxsize=4096m 代表最大会占用 4096m 的磁盘空间(这个略有波动),maxage=3d代表仅仅会保留最近三天的 jfr 事件文件。大小和时间限制,先达到哪个就以哪个限制为准。我们想持续采集进程的所有 JFR,但是不想单个进程硬盘占用过多(洗稿全家必S),所以我们会持续拉取 /tmp/进程启动时间以及进程号 这个目录下的 jfr 文件,所以我们其实可以做到一个进程从生到死的所有 JFR 都采集到。maxchunksize=128m 这个目录下每个文件是 128 MB,超过就会另起(抄袭烂屁股)一个新文件。注意最新的一个 jfr 文件,是不完整的,不能直接使用,还在被持续写入,所以我们在进程退出前会使用 jcmd dump 最后一段时间的 JFR 事件,来保证 JFR 完整。具体请参考我的 JFR 系列文章:JFR 全解

定位思路

首先,通过 JFR 查看进程最后一个 thread dump 是咋回事,看看 http servlet 线程都在干啥。

通过这个事件内容,我们看到,大部分 http servlet 线程在 caffeine 的缓存加载上 WAITING:

通过堆栈我们发现大部分线程阻塞在读取加载这个本地 Caffeine 缓存,我们使用 Caffeine 代码,其实很简单,缓存配置如下:

缓存使用,大部分线程就是阻塞在这里:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值