ririliu commented on issue #1784: URL: https://github.com/apache/dubbo/issues/1784#issuecomment-2456664658
> 我这边也遇到类似的问题,使用的版本 2.7.12(consumer和provider都是此版本)。 问题表现为 provider 侧的日志和指标显示请求处理都正常,但是consumer侧报请求超时,触发重试。 > > 报错的堆栈关键词如下。 > > ``` > org.apache.dubbo.rpc.RpcException: Invoke remote method timeout. method: XXXXX, provider: dubbo://打码打码打码:20880/XXXXXX > .... > at org.apache.dubbo.rpc.protocol.AsyncToSyncInvoker.invoke(AsyncToSyncInvoker.java:70) > at org.apache.dubbo.rpc.listener.ListenerInvokerWrapper.invoke(ListenerInvokerWrapper.java:78) > at com.alibaba.dubbo.rpc.Invoker$CompatibleInvoker.invoke(Invoker.java:55) > .... > ``` > > 经过排查,发现是版本 [2.7.7, 2.7.15] 区间的 bug 造成的。 这些 dubbo 版本会在 Provider 侧的 IO 线程中使用到 Hessian2ObjectOutput,Hessian2ObjectOutput 对象会包含一个 Hessian2Output 对象并且使用 ThreadLocal 进行缓存,Hessian2Output 又会维护一个 IdentifyIntMap,每次复用到 Hessian2Output 对象时,会对这个 IdentifyIntMap 进行遍历操作。 见:https://github.com/apache/dubbo-hessian-lite/blob/master/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/io/Hessian2Output.java 的 init 方法,最终会调用到 IdentifyIntMap 的 clear() 方法。  记住这个 for 循环。 > > 这个 IdentifyIntMap 是 Hessian2 序列化时辅助计算(大概是此作用)的,当序列化的内容较大(尤其是嵌套比较深的时候),这个 IdentifyIntMap 会进行扩容,扩容规则是 当前总容量的 1/4,小于等于使用量时,扩容为当前总容量的 4倍 。 见:https://github.com/apache/dubbo-hessian-lite/blob/master/hessian-lite/src/main/java/com/alibaba/com/caucho/hessian/util/IdentityIntMap.java put方法  > > map的容量会不断撑大,每次使用又会遍历它重置,它又是运行在 netty 的 io 线程上,所以一旦map的容量超过某个阈值时,io线程就会拥塞,如下所示。  注意� ��序里运行的Hession2类库版本和上述截图不一致,所以行数有偏差,但是逻辑是一样的,都是卡在for循环遍历。 > > heap dump 结果,发现这个 map 的元素已经被撑大到 400w+ 。  > > 等于是出现故障时 IO线程 已经水泄不通了。 排查同期的 provider 侧 内存占用,开始故障后老年代持续增长,说明响应淤积住了。 > > 问题解决:provider侧升级到 2.7.16 即以上版本就能修复这个问题,此版本开始移除了对 Hessian2ObjectOutput 对象的线程级缓存。 > > #[5889](https://github.com/apache/dubbo/pull/5889) 引入 #[10231](https://github.com/apache/dubbo/pull/10231) 修复 > > 遗留问题:为什么 provider 侧的指标都正常? 根据官方的线程模型示意图:https://cn.dubbo.apache.org/en/docs3-v2/java-sdk/advanced-features-and-usage/performance/threading-model/provider/  > > dubbo 线程处理好业务之后,是将 response 对象丢给 IO线程处理,IO线程处理 serialize 过程(即序列化,本次的故障点),业务逻辑处理和 IO输出异步化了。所以我们基于 dubbo 线程的 filter 的指标采集,以及在 dubbo 线程中所做的日志打印,完全感知不到异常。 感谢大佬的这篇回复,搜关键字进来发现是一模一样的问题,省了N个小时的排查,分析的也相当完整,一般真的不太会想到是io线程的一些动作引起的 -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
