docker容器中使用java8并行流遇到的坑(线上)

docker容器中使用java8并行流遇到的坑(线上),第1张

docker容器中使用java8并行流遇到的坑(线上) 1.问题
最近接到用户报障,线上某个接口频频超时,故拎出代码,大致如下
list.parallelStream().map(c -> {c.httpGet()}
上面的代码大致意思是并行流循环list,然后去调用一个第三方接口,用这种做法来达到多线程的方式调用第三方接口。
首先承认的是这种写法的人只是想实现某个功能,而没有真实的高并发编程经验和toC经验。
博主回想以前在某互联网公司对于此类接口,统称为“重服务”。如何优化这种场景本篇不提,只是想看看为什么接口会超时。
2.分析过程

分析:

  1.查看调用链

    查看调用链发现调用链显示串行循环调用三方接口100多次,每次大概500ms所以统计下大概50几秒,而ng侧会在调用超过30ms切掉本次调用

    当时心里一想这不是java8的并行流吗,为什么串行循环调用。而不是并行去调用。一度怀疑调用链出现问题,当然万万不可怀疑是jdk问题。

   2.分析源码

 java8的流是如上面图结构,最后走的公共线程池是ForkJoinPool,而这个ForkJoinPool的初始化线程池数量为:

再深入到这个方法 ForkJoinPool makeCommonPool() {}

return new ForkJoinPool(parallelism, (ForkJoinPool.ForkJoinWorkerThreadFactory)factory, handler, 0, "ForkJoinPool.commonPool-worker-");

通过上图可以看到:

Runtime.getRuntime().availableProcessors() - 1 如果大于0那么就是这个数,否则 parallelism为1

  3.查看日志:

     截图当时未保存确实显示的是如下一个线程,验证猜想

ForkJoinPool.commonPool-worker-0

4.进一步验证

线上打印Runtime.getRuntime().availableProcessors() 

3.解决

  1.临时解决方案

     增加jvm参数-Djava.util.concurrent.ForkJoinPool.common.parallelism=10,为parallelStream增加自定义线程池线程数量,这个是全局的慎用

  2. 定义自定义的线程池,来代替java8默认线程池

4.为什么Runtime.getRuntime().availableProcessors() =1

需要指明的是本项目是在docker容器里部署

jdk <1.8.0_131 在docker内 获取的是宿主机上的内核数

jdk >=1.8.0_131 在docker内 获取的是docker被限制的内核数

以下2篇文章可以很好的解答这个问题

spark docker java kubernetes 获取cpu内核/线程数问题_weixin_30905133的博客-CSDN博客

https://blogs.oracle.com/java/post/java-se-support-for-docker-cpu-and-memory-limits

您的支持是我创作最大的动力,敬礼  

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zaji/5707094.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-12-17
下一篇2022-12-17

发表评论

登录后才能评论

评论列表(0条)

    保存