范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

MQJDKBug导致线程阻塞案例分析

  背景介绍业务介绍
  在某学习APP浏览文章,客户端会将浏览的文章信息上传到服务端,服务端将浏览信息最终存储到HBase;
  在某学习APP首页点击【我的】->【历史】,会展示用户浏览文章的历史记录。 技术介绍
  服务端的服务是【阅读历史离线服务】,从metaq消费用户阅读文章的信息,解析、处理相关业务逻辑,最后存储到HBase。 问题现象ECS监控
  两台机器【xx-xxxx-xxx-xxx-xxx-xxx-6、xx-xxx-xxx-xxx-xxx-xxx-1】在早高峰的时候Load很高,CPU使用率正常。
  metaq监控
  造成消息消费的慢,每天早上都有大量消息堆积,导致用户看不到自己的阅读历史。 问题分析基本情况
  【阅读历史离线服务】共有x台ECS,每台ECS配置是8c16g。其中x台机器正常,2台机器不正常。 排查思路找不同
  分析不正常机器与正常机器有哪些差异:对比了【应用程序版本】、【应用程序配置】、【JVM配置参数】、【JDK版本】、【操作系统版本】,发现【JDK版本】不一致。
  正常机器: openjdk version "1.8.0_171" OpenJDK Runtime Environment (build 1.8.0_171-b10) OpenJDK 64-Bit Server VM (build 25.171-b10, mixed mode)
  异常机器: openjdk version "1.8.0_222" OpenJDK Runtime Environment (build 1.8.0_222-b10) OpenJDK 64-Bit Server VM (build 25.222-b10, mixed mode)
  到此初步定位不同机器运行状态不一致的现象是由于【JDK版本】不一致造成的,所以将【问题机器的JDK版本】替换为【正常机器的JDK版本】问题就可以解决了。 定位问题代码
  但是问题的根因还需要尝试排查一下,既然是【JDK版本】不一致造成的,那么会不会是【1.8.0_222】这个版本中有BUG,刚好我们写的程序触发了这个BUG?
  所以接下来需要弄清楚程序运行过程中执行了哪些业务逻辑、这些业务逻辑涉及到了哪些JDK API,直接想到的工具是arthas profiler,下面是抓到的热点方法。
  通过对比【异常机器】与【正常机器】的热点方法,发现Runtime.getRuntime().availableProcessors()很可疑:
  业务相关代码: CompletableFuture completableFuture = //业务逻辑,调用hbase-client中api completableFuture.whenCompleteAsync((result, t) -> {    //业务逻辑处理             }, Pool.getSubmitPool()).exceptionally((t) -> {    //业务逻辑处理 }).get();
  CompletableFuture相关代码: /**      * Waits if necessary for this future to complete, and then      * returns its result.      *      * @return the result value      * @throws CancellationException if this future was cancelled      * @throws ExecutionException if this future completed exceptionally      * @throws InterruptedException if the current thread was interrupted      * while waiting      */     public T get() throws InterruptedException, ExecutionException {         Object r;         return reportGet((r = result) == null ? waitingGet(true) : r);     } /**      * Returns raw result after waiting, or null if interruptible and      * interrupted.      */     private Object waitingGet(boolean interruptible) {         Signaller q = null;         boolean queued = false;         int spins = -1;         Object r;         while ((r = result) == null) {             if (spins < 0)                 spins = (Runtime.getRuntime().availableProcessors() > 1) ?                     1 << 8 : 0; // Use brief spin-wait on multiprocessors             else if (spins > 0) {                 if (ThreadLocalRandom.nextSecondarySeed() >= 0)                     --spins;             }             else if (q == null)                 q = new Signaller(interruptible, 0L, 0L);             else if (!queued)                 queued = tryPushStack(q);             else if (interruptible && q.interruptControl < 0) {                 q.thread = null;                 cleanStack();                 return null;             }             else if (q.thread != null && result == null) {                 try {                     ForkJoinPool.managedBlock(q);                 } catch (InterruptedException ie) {                     q.interruptControl = -1;                 }             }         }         if (q != null) {             q.thread = null;             if (q.interruptControl < 0) {                 if (interruptible)                     r = null; // report interruption                 else                     Thread.currentThread().interrupt();             }         }         postComplete();         return r;     } 猜测验证public class Processors {     public static void main(String []args) {         int availableProcessors = Runtime.getRuntime().availableProcessors();         System.out.println("Available Processors: " + availableProcessors);                  for(int i = 0;i < availableProcessors;i++){             Thread t = new Thread(()-> {                     while (true){                         try {                             int ps = Runtime.getRuntime().availableProcessors();                             Thread.sleep(1L);                         }catch (Exception e){                             e.printStackTrace();                         }                     }             });              t.start();         }     } }
  将验证代码在【JDK版本】为【1.8.0_222】的机器上运行,随即复现了线上问题。 定位根因
  那么【1.8.0_222】与【1.8.0_171】版本在Runtime.getRuntime().availableProcessors()的实现上有什么差别呢?【1.8.0_222】增加了容器环境的逻辑,比【1.8.0_171】复杂了很多。
  最后我们看看在https://bugs.openjdk.java.net/的解释吧。
  总结:
  Runtime.getRuntime().availableProcessors()在不同JDK版本上的实现是没有问题的,CompletableFuture.waitingGet在【1.8.0_222】版本上,没有测试到Runtime.getRuntime().availableProcessors()对性能的影响,导致了性能问题。 解决方法
  openjdk在1.8.0_191~1.8.0_222之间的版本都存在问题,换成1.8.0_191之前,或1.8.0_232及以后的版本可以。 问题根因
  CompletableFuture.get()的实现方式在一些jdk版本存在缺陷,
  详情见:[JDK-8227018] CompletableFuture should not call Runtime.availableProcessors on fast path - Java Bug System

地球通信被切断,中国地面已联系不到天问一号,究竟发生了什么近日,中国天问一号和祝融火星车已经与地面彻底失联,在控制中心的测控信号显示屏上,只有一条毫无意义的噪声波形,所有测控频道都已经被高强度的噪声淹没,也就是说地球和火星之间的通信受到了10975米马里亚纳海沟,科学家不希望看到的东西出现人类该警惕了阅读本文前,请您先点击上面的关注,这样您就可以继续免费收到最新文章了,请放心关注。感谢大家的阅读。随着各国科技水平的提升,各国探索世界的领域在向更多领域扩散,我国在不断发展航天事业小行星撞击地球的连锁反应,从几亿年前直到今天都未消停大洪水是小行星撞击天山给人类带来的第二大灾难。在旧约。创世纪中原文为耶和华见人在地球上罪恶极大,于是宣布将用洪水,毁灭天下地上有血有肉有气息的活物,无一不死。大洪水发生过的证据是世太阳系绕银河系公转一圈,引发生物大灭绝?我们人类命运又将如何众所周知,我们的地球在绕太阳公转的同时,太阳系也在绕银河系中心高速公转,太阳系绕银河系公转速度大约是250千米每秒。我们的太阳位于距离银河系中心约2。7万光年距边缘大约2。3万光年今天把老电脑安装了Win11简直太惊喜了重启后,插上U盘,进入PE,我用的是微PE。选择uefi成功进入PE系统把原来的C盘格式化,我的电脑不习惯分区,就一个盘开始格式化格式化成功打开Windows安装工具绿灯全亮,开始安全易用的小耳勺,让耳朵更舒服,素诺智能可视耳勺体验掏耳朵的时候我们一般都会用耳勺,有些朋友可能习惯使用棉签,不过就安全性来说,两者都不是令人满意的选择。好在随着技术的进步,现在市面上出现了很多带有摄像头的耳勺,我最近在用的素诺智能全球半导体霸主换人,2nm芯片箭在弦上如果我问你目前全球最强的半导体芯片企业是谁?你可能会说是英特尔或者是高通,要不就是台积电?都不是,其实是三星。从收入的角度看,早在2017年,三星就第一次在半导体收入上超过Inte9月京东手机销量国产百元机打败iPhone13,华为小米跌出榜单很多消费者都喜欢把销量排行榜作为购机的重要参考因素,因为一般情况下,销量越好的手机就证明购买的人越多,越受人欢迎的东西自然不会出错。无独有偶,近日知名数码达人小乙MAX公布了202冲牙器2。0时代,素诺冲牙器给你看得见的体验口腔问题一直是困扰着我们的健康的大问题,不要小瞧了口腔问题,可以说牙齿不健康,可以让你寝食难安。我们传统上的刷牙不足以解决我们的口腔问题,很多人会选择牙线或者漱口水。但是依然不好解历史上真实的长津湖之战,中美王牌军队间的巅峰对决1949年10月1日新中国成立的时候,毛主席站在天安门城楼上向全世界宣布中国人民从此站起来了!日本人不信,苏联人不信,美国人更加不信,一个被西方欺辱了100多年的国家,一个绝大多数十分钟带你了解中国简史,从原始社会到民国成立中华上下五千年排版芷烨文史文章字数3300阅读时长12分钟我国原始社会始于人从动物界分离,止于阶级和国家的形成。原始社会时期是人类发展的幼儿期,从公元170万年前公元前2070年,这个时代大约经
千元防晒衣,谁买谁是大怨种今年夏天特别晒,防晒衣成了我们的刚需。视觉中国夏季的烈日像一炉沸腾的钢水。紫外线是人类公敌,轻则加速皮肤老化,重则伤害神经系统,但在此之前,晒黑便足够令人焦虑。除了涂防晒霜,人们还官宣!又是前叉,报销了吧?有毒啊公牛今天,公牛官方宣布球队前锋贾斯汀刘易斯在训练中遭遇右膝前交叉韧带伤势,将会在未来数周之内确定手术,将会无限期休战。麻了麻了!又是前叉,还要在未来几周之内才能手术,从这些字眼大概都能范尼谈弗格森现场看自己执教这令我倍感自豪,从他身上受益良多直播吧8月17日讯据每日邮报报道,弗格森近日在现场观看了范尼所执教的埃因霍温队的比赛。范尼在接受采访时表示,弗格森能够亲临现场,让自己感到非常的自豪。据悉,在本周二的欧冠附加赛第一这菜几分钟搞定儿子每周吃三次都不腻,酸酸甜甜拌米饭能吃一大碗大家好,今天来跟大家分享一道特别受小朋友欢迎的家常菜浓汤番茄肥牛卷。番茄应该算是我儿子从会吃饭开始到现在最爱吃的一种蔬菜了,用番茄做的菜他也都喜欢,可能是小朋友都会比较喜欢这种酸酸千元防晒衣,谁买谁是大怨种今年夏天特别晒,防晒衣成了我们的刚需。视觉中国夏季的烈日像一炉沸腾的钢水。紫外线是人类公敌,轻则加速皮肤老化,重则伤害神经系统,但在此之前,晒黑便足够令人焦虑。除了涂防晒霜,人们还官宣!又是前叉,报销了吧?有毒啊公牛今天,公牛官方宣布球队前锋贾斯汀刘易斯在训练中遭遇右膝前交叉韧带伤势,将会在未来数周之内确定手术,将会无限期休战。麻了麻了!又是前叉,还要在未来几周之内才能手术,从这些字眼大概都能范尼谈弗格森现场看自己执教这令我倍感自豪,从他身上受益良多直播吧8月17日讯据每日邮报报道,弗格森近日在现场观看了范尼所执教的埃因霍温队的比赛。范尼在接受采访时表示,弗格森能够亲临现场,让自己感到非常的自豪。据悉,在本周二的欧冠附加赛第一夏天贴一贴冬天少生病三伏贴是中医的一种贴敷疗法,运用冬病夏治的中医理论,利用每年农历夏季三伏对特定穴位进行贴敷,使药物持续性刺激穴位,疏通经络,调节脏腑功能,从而达到预防和治疗疾病的效果。中药敷贴对儿夏天贴一贴冬天少生病三伏贴是中医的一种贴敷疗法,运用冬病夏治的中医理论,利用每年农历夏季三伏对特定穴位进行贴敷,使药物持续性刺激穴位,疏通经络,调节脏腑功能,从而达到预防和治疗疾病的效果。中药敷贴对儿阵容大变,下赛季杜指该何去何从要说今年夏天,CBA休赛期可谓是风云突变,各大球队对球星的交易进行的是如火似茶,其中不乏许多我们熟知的巨星,如广东队的周琦,和辽宁队郭艾伦。以及现在深陷交易流言中的赵睿。当家球星的都是首次总决赛,07詹姆斯和塔图姆谁更拉胯?没对比就没尴尬虽然今年的总决赛已经结束了,但是很多人对于勇士PK凯尔特人这一轮系列赛津津乐道道,毕竟这一个总冠军,对于库里来说具有非凡的意义。而凯尔特人之所以输球,在一定程度上也是因为球队的当家