包阅导读总结
1. `JSF 接口`、`线程池`、`Redis 版本升级`、`读锁写锁`、`异常排查`
2. 本文主要讲述在配合 R2m 升级 Redis 版本过程中,JSF 接口出现异常,通过排查发现线程卡在获取读锁处,原因是写锁未释放及线程池使用问题,最终定位并复盘。
3.
– 问题背景
– 在 R2m 升级 Redis 版本时,上游反馈调用 JSF 接口报错,部分节点持续出现问题,下线有问题节点后业务恢复。
– 排查步骤
– 推测系统启动时分配的 JSF 线程池大小固定,流量大时无线程处理请求。
– 借助工具分析栈信息,发现线程卡在 JedisClusterInfoCachegetSlaveOfSlotFromDc 方法。
– 推测有业务获取写锁未释放且读锁未设置超时。
– 定位到更新拓扑的定时任务获取写锁,且日志异常。
– 发现 parallelStream().forEach 和 caffeine 数据刷新默认使用共用线程池,可能导致线程等待。
– 验证了线程池活跃线程等待读锁,topo-updater 卡在业务处理逻辑中。
– 复盘
– 此问题特定场景小概率出现,后续将异步更新拓扑改为同步处理。
– 注意 Java 异步处理的线程和线程池使用及异常处理。
– 强调做好监控及时发现和处理问题。
思维导图:
文章地址:https://mp.weixin.qq.com/s/E0zAKx4-CZCQ1KQOtn898A
文章来源:mp.weixin.qq.com
作者:京东科技??田蒙
发布时间:2024/7/5 10:19
语言:中文
总字数:2139字
预计阅读时间:9分钟
评分:84分
标签:JSF,线程池耗尽,排查问题,Redis升级,分布式缓存
以下为原文内容
本内容来源于用户推荐转载,旨在分享知识与观点,如有侵权请联系删除 联系邮箱 media@ilingban.com

问题背景
理解,首先 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 22003
24-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
排查步骤
理解,首先 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 22003
24-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
排查步骤
1)借助SGM打印栈信息
2)分析栈信息
2.1)分析线程状态
通过工具可以定位到JSF线程大部分卡在JedisClusterInfoCache#getSlaveOfSlotFromDc方法,如图:
2.2)分析线程夯住的方法
getSlaveOfSlotFromDc在方法入口就需要获取读锁,同时在全局变量声明了读锁和写锁:
2.3)从业务的角度分析持有写锁的逻辑
向中间件研发寻求帮助,经过排查,定位到有个更新拓扑的定时任务,执行时会先获取写锁,根据该消息,定位到任务的栈信息:
2.4)深入挖掘原因
经过查找资料确认,如果没有指定,那么parallelStream().forEach会使用ForkJoinPool.commonPool这个默认的线程池去处理任务,该线程池默认设置(容器核心数-1)个活跃线程。同时caffeine数据过期后会异步刷新数据,如果没有指定线程池,它默认也会使用ForkJoinPool.commonPool()来执行异步线程。那么就有概率出现获取到写锁的线程无法获取执行权,获取执行权的线程无法获取到读锁。
2.5)验证
3个ForkJoinPool.commonPool-worker的确都夯在获取redis连接处,线程池的活跃线程都在等待读锁
复盘
3)做好监控,能第一时间发现问题并处理问题。
▪功能支撑:会员成长体系、等级计算策略、权益体系、营销底层能力支持
▪用户活跃:会员关怀、用户触达、活跃活动、业务线交叉获客、拉新促活