进程还在,JSF接口不干活了,这你敢信?

进程还在,JSF接口不干活了,这你敢信?



01 

  

问题背景

  



理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将

应用在配合R2m(R2M:京东内部一款基于Redis研发的,具备高性能、高可用、在线伸缩能力的分布式缓存服务)升级redis版本的过程中,上游反馈调用接口报错,RpcException:[Biz thread pool of provider has been exhausted],通过监控系统和日志系统定位到现象只出现在一两个节点,并持续出现。第一时间通过JSF(JSF:中文名-杰夫,是Jingdong Service Framework (京东服务框架)的缩写,完全自主研发的高性能服务框架)将有问题的节点下线,保留现场,业务恢复。

报错日志如下:
24-03-13 02:21:20.188 [JSF-SEV-WORKER-57-T-5] ERROR BaseServerHandler - handlerRequest error msg:[JSF-23003]Biz thread pool of provider has been exhausted, the server port is 2200324-03-13 02:21:20.658 [JSF-SEV-WORKER-57-T-5] WARN BusinessPool - [JSF-23002]Task:com.alibaba.ttl.TtlRunnable - com.jd.jsf.gd.server.JSFTask@0 has been reject for ThreadPool exhausted! pool:80, active:80, queue:300, taskcnt: 1067777



02 

  

排查步骤

  



理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将

从现象开始推测原因,系统启动时,会给JSF线程池分配固定的大小,当线程都在工作的时,外部流量又打进来,那么会没有线程去处理请求,此时会有上述的异常。那么JSF线程在干什么呢?

1)借助SGM打印栈信息

进程还在,JSF接口不干活了,这你敢信?

2)分析栈信息

可以用在线分析工具:http://spotify.github.io/threaddump-analyzer/

2.1)分析线程状态

通过工具可以定位到JSF线程大部分卡在JedisClusterInfoCache#getSlaveOfSlotFromDc方法,如图:

进程还在,JSF接口不干活了,这你敢信?

进程还在,JSF接口不干活了,这你敢信?

进程还在,JSF接口不干活了,这你敢信?

进程还在,JSF接口不干活了,这你敢信?

2.2)分析线程夯住的方法

getSlaveOfSlotFromDc在方法入口就需要获取读锁,同时在全局变量声明了读锁和写锁:

进程还在,JSF接口不干活了,这你敢信?

进程还在,JSF接口不干活了,这你敢信?
此时对问题有一个大体的了解,大概推测:getSlaveOfSlotFromDc是获取redis连接池,该方法入口处需要获取读锁,由于读锁之间不会互斥,所以猜测有业务获取到写锁后没有释放。同时读锁没有设置超时时间,所以导致杰夫线程处理业务时卡在获取读锁处,无法释放。

2.3)从业务的角度分析持有写锁的逻辑

向中间件研发寻求帮助,经过排查,定位到有个更新拓扑的定时任务,执行时会先获取写锁,根据该消息,定位到任务的栈信息:

进程还在,JSF接口不干活了,这你敢信?
代码截图:

进程还在,JSF接口不干活了,这你敢信?

进程还在,JSF接口不干活了,这你敢信?

进程还在,JSF接口不干活了,这你敢信?
从日志验证:日志只打印更新拓扑的日志,没有打印更新成功的日志,且02:20分以后r2m-topo-updater就不在打印日志

进程还在,JSF接口不干活了,这你敢信?

2.4)深入挖掘原因

虽然现象已经可以推测出来,但是对问题的原因还是百思不得其解,难道parallelStream().forEach存在bug?难道有远程请求,没有设置超时时间?……

经过查找资料确认,如果没有指定,那么parallelStream().forEach会使用ForkJoinPool.commonPool这个默认的线程池去处理任务,该线程池默认设置(容器核心数-1)个活跃线程。同时caffeine数据过期后会异步刷新数据,如果没有指定线程池,它默认也会使用ForkJoinPool.commonPool()来执行异步线程。那么就有概率出现获取到写锁的线程无法获取执行权,获取执行权的线程无法获取到读锁。

进程还在,JSF接口不干活了,这你敢信?

2.5)验证

3个ForkJoinPool.commonPool-worker的确都夯在获取redis连接处,线程池的活跃线程都在等待读锁

进程还在,JSF接口不干活了,这你敢信?
本地caffeine缓存没有设置自定义线程池

进程还在,JSF接口不干活了,这你敢信?
topo-updater夯在foreach业务处理逻辑中
进程还在,JSF接口不干活了,这你敢信?


03 

  

复盘  



理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将
1)此问题在特定的使用场景下才会小概率出现,非常感谢中间件团队一起协助定位问题,后续也将异步更新拓扑改为同步处理。
2)Java提供了很多异步处理的能力,但是异常处理也代表需要开启线程或者使用共用的线程池,也需要注意。

3)做好监控,能第一时间发现问题并处理问题。

进程还在,JSF接口不干活了,这你敢信?

进程还在,JSF接口不干活了,这你敢信?

推荐阅读
生成式推荐系统与京东联盟广告-综述与应用
2024 「全球软件研发技术大会」—刘兴东分享京东的AIGC革新之旅
利用大模型服务一线小哥的探索与实践
京东鸿蒙原生应用尝鲜版上架!
打SAS化服务的会员徽章体系,可以作为标准的产方👇 点击”阅读原文“查看技术类精选书单案统一对外输出。结合现有平台通用能力,实现会员行为全路径覆盖,并能结合企业自身业务特点,规划相应的会员精准营销活动,提升会员忠诚度和业务的持续增长。
底层能力:维护用户基础数据、行为数据建模、用户画像分析、精准营销策略的制定

功能支撑:会员成长体系、等级计算策略、权益体系、营销底层能力支持

▪用户活跃:会员关怀、用户触达、活跃活动、业务线交叉获客、拉新促活

‍‍

本篇文章来源于微信公众号:京东技术

本文来自投稿,不代表TakinTalks稳定性技术交流平台立场,如若转载,请联系原作者。

(0)
上一篇 2024年6月28日 上午8:30

相关推荐

发表评论

邮箱地址不会被公开。